blob: 68daf44b19a5e89131612aaa34dd64b79aa3eb5b [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;
Mathew Inwood61e8ae62018-08-14 14:17:44 +010025import android.annotation.UnsupportedAppUsage;
Adam Powell371a8092014-06-20 12:51:12 -070026import android.content.Context;
George Mountf1d88e62017-03-13 10:47:57 -070027import android.content.pm.ApplicationInfo;
Dianne Hackborn9d071802010-12-08 14:49:15 -080028import android.content.res.Configuration;
Adam Powelle01f5952016-02-23 15:25:42 -080029import android.content.res.Resources.NotFoundException;
Dianne Hackbornf121be72010-05-06 14:10:32 -070030import android.content.res.TypedArray;
George Mountf1d88e62017-03-13 10:47:57 -070031import android.os.Build;
Dianne Hackborn2dedce62010-04-15 14:45:25 -070032import android.os.Bundle;
Dianne Hackbornf43a33c2012-09-27 00:48:11 -070033import android.os.Debug;
Dianne Hackborn3a57fb92010-11-15 17:58:52 -080034import android.os.Looper;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -070035import android.os.Parcel;
36import android.os.Parcelable;
George Mountc21dfd92017-01-05 16:50:25 -080037import android.util.ArraySet;
Adam Powell371a8092014-06-20 12:51:12 -070038import android.util.AttributeSet;
Dianne Hackborna2ea7472010-12-20 12:10:01 -080039import android.util.DebugUtils;
Dianne Hackborn5ae74d62010-05-19 19:14:57 -070040import android.util.Log;
Dianne Hackborn5d9d03a2011-01-24 13:15:09 -080041import android.util.LogWriter;
Adam Powell38c67ff2016-10-28 10:24:40 -070042import android.util.Pair;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -070043import android.util.SparseArray;
Adam Powell14874662013-07-18 19:42:41 -070044import android.util.SuperNotCalledException;
Adam Powell371a8092014-06-20 12:51:12 -070045import android.view.LayoutInflater;
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -070046import android.view.Menu;
47import android.view.MenuInflater;
48import android.view.MenuItem;
Dianne Hackborn5ae74d62010-05-19 19:14:57 -070049import android.view.View;
Dianne Hackborn2dedce62010-04-15 14:45:25 -070050import android.view.ViewGroup;
George Mount86bfc662016-07-12 16:06:06 -070051
Dianne Hackborn8c841092013-06-24 13:46:13 -070052import com.android.internal.util.FastPrintWriter;
Dianne Hackborn2dedce62010-04-15 14:45:25 -070053
Dianne Hackborn625ac272010-09-17 18:29:22 -070054import java.io.FileDescriptor;
55import java.io.PrintWriter;
Dianne Hackborn2dedce62010-04-15 14:45:25 -070056import java.util.ArrayList;
Dianne Hackbornd173fa32010-12-23 13:58:22 -080057import java.util.Arrays;
George Mountc7146be2017-03-29 14:13:03 +000058import java.util.Collections;
Todd Kennedya5fc6f02015-04-14 18:22:54 -070059import java.util.List;
Adam Powell38c67ff2016-10-28 10:24:40 -070060import java.util.concurrent.CopyOnWriteArrayList;
Dianne Hackborn2dedce62010-04-15 14:45:25 -070061
Dianne Hackbornb7a2e472010-08-12 16:20:42 -070062/**
63 * Interface for interacting with {@link Fragment} objects inside of an
64 * {@link Activity}
Joe Fernandezb54e7a32011-10-03 15:09:50 -070065 *
66 * <div class="special reference">
67 * <h3>Developer Guides</h3>
68 * <p>For more information about using fragments, read the
Andrew Solovayf5396802016-08-26 15:46:38 -070069 * <a href="{@docRoot}guide/components/fragments.html">Fragments</a> developer guide.</p>
Joe Fernandezb54e7a32011-10-03 15:09:50 -070070 * </div>
Dianne Hackborn7871bad2011-12-12 15:19:26 -080071 *
72 * While the FragmentManager API was introduced in
73 * {@link android.os.Build.VERSION_CODES#HONEYCOMB}, a version of the API
74 * at is also available for use on older platforms through
75 * {@link android.support.v4.app.FragmentActivity}. See the blog post
76 * <a href="http://android-developers.blogspot.com/2011/03/fragments-for-all.html">
77 * Fragments For All</a> for more details.
Ian Lake0a1feb82017-11-13 10:26:46 -080078 *
Ian Lake1f4e67b2017-12-18 10:36:18 -080079 * @deprecated Use the <a href="{@docRoot}tools/extras/support-library.html">Support Library</a>
80 * {@link android.support.v4.app.FragmentManager} for consistent behavior across all devices
81 * and access to <a href="{@docRoot}topic/libraries/architecture/lifecycle.html">Lifecycle</a>.
Dianne Hackbornb7a2e472010-08-12 16:20:42 -070082 */
Ian Lake0a1feb82017-11-13 10:26:46 -080083@Deprecated
Dianne Hackbornab36acb2010-11-05 14:12:11 -070084public abstract class FragmentManager {
Dianne Hackbornb7a2e472010-08-12 16:20:42 -070085 /**
Dianne Hackbornc6669ca2010-09-16 01:33:24 -070086 * Representation of an entry on the fragment back stack, as created
87 * with {@link FragmentTransaction#addToBackStack(String)
88 * FragmentTransaction.addToBackStack()}. Entries can later be
Dianne Hackborn327fbd22011-01-17 14:38:50 -080089 * retrieved with {@link FragmentManager#getBackStackEntryAt(int)
Mark Dolinerd0646dc2014-08-27 16:04:02 -070090 * FragmentManager.getBackStackEntryAt()}.
Dianne Hackbornc6669ca2010-09-16 01:33:24 -070091 *
92 * <p>Note that you should never hold on to a BackStackEntry object;
93 * the identifier as returned by {@link #getId} is the only thing that
94 * will be persisted across activity instances.
Ian Lake0a1feb82017-11-13 10:26:46 -080095 *
Ian Lake1f4e67b2017-12-18 10:36:18 -080096 * @deprecated Use the <a href="{@docRoot}tools/extras/support-library.html">
97 * Support Library</a> {@link android.support.v4.app.FragmentManager.BackStackEntry}
Dianne Hackbornc6669ca2010-09-16 01:33:24 -070098 */
Ian Lake0a1feb82017-11-13 10:26:46 -080099 @Deprecated
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700100 public interface BackStackEntry {
101 /**
102 * Return the unique identifier for the entry. This is the only
103 * representation of the entry that will persist across activity
104 * instances.
105 */
106 public int getId();
107
108 /**
Dianne Hackborn6c285972011-08-29 16:53:49 -0700109 * Get the name that was supplied to
110 * {@link FragmentTransaction#addToBackStack(String)
111 * FragmentTransaction.addToBackStack(String)} when creating this entry.
112 */
113 public String getName();
114
115 /**
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800116 * Return the full bread crumb title resource identifier for the entry,
117 * or 0 if it does not have one.
118 */
119 public int getBreadCrumbTitleRes();
120
121 /**
122 * Return the short bread crumb title resource identifier for the entry,
123 * or 0 if it does not have one.
124 */
125 public int getBreadCrumbShortTitleRes();
126
127 /**
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700128 * Return the full bread crumb title for the entry, or null if it
129 * does not have one.
130 */
131 public CharSequence getBreadCrumbTitle();
132
133 /**
134 * Return the short bread crumb title for the entry, or null if it
135 * does not have one.
136 */
137 public CharSequence getBreadCrumbShortTitle();
138 }
139
140 /**
141 * Interface to watch for changes to the back stack.
Ian Lake0a1feb82017-11-13 10:26:46 -0800142 *
Ian Lake1f4e67b2017-12-18 10:36:18 -0800143 * @deprecated Use the <a href="{@docRoot}tools/extras/support-library.html">
144 * Support Library</a>
145 * {@link android.support.v4.app.FragmentManager.OnBackStackChangedListener}
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700146 */
Ian Lake0a1feb82017-11-13 10:26:46 -0800147 @Deprecated
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700148 public interface OnBackStackChangedListener {
149 /**
150 * Called whenever the contents of the back stack change.
151 */
152 public void onBackStackChanged();
153 }
154
155 /**
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700156 * Start a series of edit operations on the Fragments associated with
157 * this FragmentManager.
Dianne Hackbornfb3cffe2010-10-25 17:08:56 -0700158 *
159 * <p>Note: A fragment transaction can only be created/committed prior
160 * to an activity saving its state. If you try to commit a transaction
161 * after {@link Activity#onSaveInstanceState Activity.onSaveInstanceState()}
162 * (and prior to a following {@link Activity#onStart Activity.onStart}
163 * or {@link Activity#onResume Activity.onResume()}, you will get an error.
164 * This is because the framework takes care of saving your current fragments
165 * in the state, and if changes are made after the state is saved then they
166 * will be lost.</p>
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700167 */
Dianne Hackborn48e7b452011-01-17 12:28:35 -0800168 public abstract FragmentTransaction beginTransaction();
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700169
Dianne Hackborn17b9b812011-01-17 17:16:02 -0800170 /** @hide -- remove once prebuilts are in. */
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800171 @Deprecated
Dianne Hackborn48e7b452011-01-17 12:28:35 -0800172 public FragmentTransaction openTransaction() {
173 return beginTransaction();
174 }
175
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700176 /**
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800177 * After a {@link FragmentTransaction} is committed with
178 * {@link FragmentTransaction#commit FragmentTransaction.commit()}, it
179 * is scheduled to be executed asynchronously on the process's main thread.
180 * If you want to immediately executing any such pending operations, you
181 * can call this function (only from the main thread) to do so. Note that
182 * all callbacks and other related behavior will be done from within this
183 * call, so be careful about where this is called from.
George Mount86bfc662016-07-12 16:06:06 -0700184 * <p>
185 * This also forces the start of any postponed Transactions where
186 * {@link Fragment#postponeEnterTransition()} has been called.
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800187 *
188 * @return Returns true if there were any pending transactions to be
189 * executed.
190 */
191 public abstract boolean executePendingTransactions();
192
193 /**
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700194 * Finds a fragment that was identified by the given id either when inflated
195 * from XML or as the container ID when added in a transaction. This first
196 * searches through fragments that are currently added to the manager's
197 * activity; if no such fragment is found, then all fragments currently
198 * on the back stack associated with this ID are searched.
199 * @return The fragment if found or null otherwise.
200 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700201 public abstract Fragment findFragmentById(int id);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700202
203 /**
204 * Finds a fragment that was identified by the given tag either when inflated
205 * from XML or as supplied when added in a transaction. This first
206 * searches through fragments that are currently added to the manager's
207 * activity; if no such fragment is found, then all fragments currently
208 * on the back stack are searched.
209 * @return The fragment if found or null otherwise.
210 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700211 public abstract Fragment findFragmentByTag(String tag);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700212
213 /**
214 * Flag for {@link #popBackStack(String, int)}
215 * and {@link #popBackStack(int, int)}: If set, and the name or ID of
216 * a back stack entry has been supplied, then all matching entries will
217 * be consumed until one that doesn't match is found or the bottom of
218 * the stack is reached. Otherwise, all entries up to but not including that entry
219 * will be removed.
220 */
221 public static final int POP_BACK_STACK_INCLUSIVE = 1<<0;
222
223 /**
Ben Komalo87ffa202011-02-28 12:41:42 -0800224 * Pop the top state off the back stack. This function is asynchronous -- it
225 * enqueues the request to pop, but the action will not be performed until the
226 * application returns to its event loop.
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700227 */
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800228 public abstract void popBackStack();
229
230 /**
231 * Like {@link #popBackStack()}, but performs the operation immediately
232 * inside of the call. This is like calling {@link #executePendingTransactions()}
George Mount86bfc662016-07-12 16:06:06 -0700233 * afterwards without forcing the start of postponed Transactions.
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800234 * @return Returns true if there was something popped, else false.
235 */
236 public abstract boolean popBackStackImmediate();
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700237
238 /**
239 * Pop the last fragment transition from the manager's fragment
240 * back stack. If there is nothing to pop, false is returned.
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800241 * This function is asynchronous -- it enqueues the
242 * request to pop, but the action will not be performed until the application
243 * returns to its event loop.
244 *
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700245 * @param name If non-null, this is the name of a previous back state
246 * to look for; if found, all states up to that state will be popped. The
247 * {@link #POP_BACK_STACK_INCLUSIVE} flag can be used to control whether
248 * the named state itself is popped. If null, only the top state 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(String name, int flags);
252
253 /**
254 * Like {@link #popBackStack(String, int)}, but performs the operation immediately
255 * inside of the call. This is like calling {@link #executePendingTransactions()}
George Mount86bfc662016-07-12 16:06:06 -0700256 * afterwards without forcing the start of postponed Transactions.
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800257 * @return Returns true if there was something popped, else false.
258 */
259 public abstract boolean popBackStackImmediate(String name, int flags);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700260
261 /**
262 * Pop all back stack states up to the one with the given identifier.
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800263 * This function is asynchronous -- it enqueues the
264 * request to pop, but the action will not be performed until the application
265 * returns to its event loop.
266 *
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700267 * @param id Identifier of the stated to be popped. If no identifier exists,
268 * false is returned.
269 * The identifier is the number returned by
270 * {@link FragmentTransaction#commit() FragmentTransaction.commit()}. The
271 * {@link #POP_BACK_STACK_INCLUSIVE} flag can be used to control whether
272 * the named state itself is popped.
273 * @param flags Either 0 or {@link #POP_BACK_STACK_INCLUSIVE}.
274 */
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800275 public abstract void popBackStack(int id, int flags);
276
277 /**
278 * Like {@link #popBackStack(int, int)}, but performs the operation immediately
279 * inside of the call. This is like calling {@link #executePendingTransactions()}
George Mount86bfc662016-07-12 16:06:06 -0700280 * afterwards without forcing the start of postponed Transactions.
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800281 * @return Returns true if there was something popped, else false.
282 */
283 public abstract boolean popBackStackImmediate(int id, int flags);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700284
285 /**
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700286 * Return the number of entries currently in the back stack.
287 */
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800288 public abstract int getBackStackEntryCount();
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700289
290 /**
291 * Return the BackStackEntry at index <var>index</var> in the back stack;
Mark Dolinerd0646dc2014-08-27 16:04:02 -0700292 * where the item on the bottom of the stack has index 0.
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700293 */
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800294 public abstract BackStackEntry getBackStackEntryAt(int index);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700295
296 /**
297 * Add a new listener for changes to the fragment back stack.
298 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700299 public abstract void addOnBackStackChangedListener(OnBackStackChangedListener listener);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700300
301 /**
302 * Remove a listener that was previously added with
303 * {@link #addOnBackStackChangedListener(OnBackStackChangedListener)}.
304 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700305 public abstract void removeOnBackStackChangedListener(OnBackStackChangedListener listener);
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700306
307 /**
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700308 * Put a reference to a fragment in a Bundle. This Bundle can be
309 * persisted as saved state, and when later restoring
310 * {@link #getFragment(Bundle, String)} will return the current
311 * instance of the same fragment.
312 *
313 * @param bundle The bundle in which to put the fragment reference.
314 * @param key The name of the entry in the bundle.
315 * @param fragment The Fragment whose reference is to be stored.
316 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700317 public abstract void putFragment(Bundle bundle, String key, Fragment fragment);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700318
319 /**
320 * Retrieve the current Fragment instance for a reference previously
321 * placed with {@link #putFragment(Bundle, String, Fragment)}.
322 *
323 * @param bundle The bundle from which to retrieve the fragment reference.
324 * @param key The name of the entry in the bundle.
325 * @return Returns the current Fragment instance that is associated with
326 * the given reference.
327 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700328 public abstract Fragment getFragment(Bundle bundle, String key);
Dianne Hackborn625ac272010-09-17 18:29:22 -0700329
330 /**
George Mounte196b6f2017-04-05 13:56:37 -0700331 * Get a list of all fragments that are currently added to the FragmentManager.
George Mountc7146be2017-03-29 14:13:03 +0000332 * This may include those that are hidden as well as those that are shown.
333 * This will not include any fragments only in the back stack, or fragments that
334 * are detached or removed.
George Mounte196b6f2017-04-05 13:56:37 -0700335 * <p>
336 * The order of the fragments in the list is the order in which they were
337 * added or attached.
George Mountc7146be2017-03-29 14:13:03 +0000338 *
George Mounte196b6f2017-04-05 13:56:37 -0700339 * @return A list of all fragments that are added to the FragmentManager.
George Mountc7146be2017-03-29 14:13:03 +0000340 */
George Mounte196b6f2017-04-05 13:56:37 -0700341 public abstract List<Fragment> getFragments();
George Mountc7146be2017-03-29 14:13:03 +0000342
343 /**
Dianne Hackbornb46ed762011-06-02 18:33:15 -0700344 * Save the current instance state of the given Fragment. This can be
345 * used later when creating a new instance of the Fragment and adding
346 * it to the fragment manager, to have it create itself to match the
347 * current state returned here. Note that there are limits on how
348 * this can be used:
349 *
350 * <ul>
351 * <li>The Fragment must currently be attached to the FragmentManager.
352 * <li>A new Fragment created using this saved state must be the same class
353 * type as the Fragment it was created from.
354 * <li>The saved state can not contain dependencies on other fragments --
355 * that is it can't use {@link #putFragment(Bundle, String, Fragment)} to
356 * store a fragment reference because that reference may not be valid when
357 * this saved state is later used. Likewise the Fragment's target and
358 * result code are not included in this state.
359 * </ul>
360 *
361 * @param f The Fragment whose state is to be saved.
362 * @return The generated state. This will be null if there was no
363 * interesting state created by the fragment.
364 */
365 public abstract Fragment.SavedState saveFragmentInstanceState(Fragment f);
366
367 /**
Dianne Hackborn6d9dcbc2012-10-02 17:51:13 -0700368 * Returns true if the final {@link Activity#onDestroy() Activity.onDestroy()}
369 * call has been made on the FragmentManager's Activity, so this instance is now dead.
370 */
371 public abstract boolean isDestroyed();
372
373 /**
Adam Powell38c67ff2016-10-28 10:24:40 -0700374 * Registers a {@link FragmentLifecycleCallbacks} to listen to fragment lifecycle events
375 * happening in this FragmentManager. All registered callbacks will be automatically
376 * unregistered when this FragmentManager is destroyed.
377 *
378 * @param cb Callbacks to register
379 * @param recursive true to automatically register this callback for all child FragmentManagers
380 */
381 public abstract void registerFragmentLifecycleCallbacks(FragmentLifecycleCallbacks cb,
382 boolean recursive);
383
384 /**
385 * Unregisters a previously registered {@link FragmentLifecycleCallbacks}. If the callback
386 * was not previously registered this call has no effect. All registered callbacks will be
387 * automatically unregistered when this FragmentManager is destroyed.
388 *
389 * @param cb Callbacks to unregister
390 */
391 public abstract void unregisterFragmentLifecycleCallbacks(FragmentLifecycleCallbacks cb);
392
393 /**
Adam Powell5f3a05c2017-01-27 16:51:03 -0800394 * Return the currently active primary navigation fragment for this FragmentManager.
395 *
396 * <p>The primary navigation fragment's
397 * {@link Fragment#getChildFragmentManager() child FragmentManager} will be called first
398 * to process delegated navigation actions such as {@link #popBackStack()} if no ID
399 * or transaction name is provided to pop to.</p>
400 *
401 * @return the fragment designated as the primary navigation fragment
402 */
403 public abstract Fragment getPrimaryNavigationFragment();
404
405 /**
Dianne Hackborn625ac272010-09-17 18:29:22 -0700406 * Print the FragmentManager's state into the given stream.
407 *
408 * @param prefix Text to print at the front of each line.
409 * @param fd The raw file descriptor that the dump is being sent to.
410 * @param writer A PrintWriter to which the dump is to be set.
Dianne Hackborn30d71892010-12-11 10:37:55 -0800411 * @param args Additional arguments to the dump request.
Dianne Hackborn625ac272010-09-17 18:29:22 -0700412 */
Dianne Hackbornab36acb2010-11-05 14:12:11 -0700413 public abstract void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args);
Dianne Hackborna2ea7472010-12-20 12:10:01 -0800414
415 /**
416 * Control whether the framework's internal fragment manager debugging
417 * logs are turned on. If enabled, you will see output in logcat as
418 * the framework performs fragment operations.
419 */
420 public static void enableDebugLogging(boolean enabled) {
421 FragmentManagerImpl.DEBUG = enabled;
422 }
Adam Powellf0f5fff2011-08-01 13:42:50 -0700423
424 /**
425 * Invalidate the attached activity's options menu as necessary.
426 * This may end up being deferred until we move to the resumed state.
427 */
428 public void invalidateOptionsMenu() { }
Adam Powell38c67ff2016-10-28 10:24:40 -0700429
430 /**
George Mount27b0dc02017-02-21 10:24:09 -0800431 * Returns {@code true} if the FragmentManager's state has already been saved
432 * by its host. Any operations that would change saved state should not be performed
433 * if this method returns true. For example, any popBackStack() method, such as
434 * {@link #popBackStackImmediate()} or any FragmentTransaction using
435 * {@link FragmentTransaction#commit()} instead of
436 * {@link FragmentTransaction#commitAllowingStateLoss()} will change
437 * the state and will result in an error.
438 *
439 * @return true if this FragmentManager's state has already been saved by its host
440 */
441 public abstract boolean isStateSaved();
442
443 /**
Adam Powell38c67ff2016-10-28 10:24:40 -0700444 * Callback interface for listening to fragment state changes that happen
445 * within a given FragmentManager.
Ian Lake0a1feb82017-11-13 10:26:46 -0800446 *
Ian Lake1f4e67b2017-12-18 10:36:18 -0800447 * @deprecated Use the <a href="{@docRoot}tools/extras/support-library.html">
448 * Support Library</a>
449 * {@link android.support.v4.app.FragmentManager.FragmentLifecycleCallbacks}
Adam Powell38c67ff2016-10-28 10:24:40 -0700450 */
Ian Lake0a1feb82017-11-13 10:26:46 -0800451 @Deprecated
Adam Powell74827260a2016-11-16 16:20:45 -0800452 public abstract static class FragmentLifecycleCallbacks {
Adam Powell38c67ff2016-10-28 10:24:40 -0700453 /**
454 * Called right before the fragment's {@link Fragment#onAttach(Context)} method is called.
455 * This is a good time to inject any required dependencies for the fragment before any of
456 * the fragment's lifecycle methods are invoked.
457 *
458 * @param fm Host FragmentManager
459 * @param f Fragment changing state
460 * @param context Context that the Fragment is being attached to
461 */
462 public void onFragmentPreAttached(FragmentManager fm, Fragment f, Context context) {}
463
464 /**
465 * Called after the fragment has been attached to its host. Its host will have had
466 * <code>onAttachFragment</code> called before this call happens.
467 *
468 * @param fm Host FragmentManager
469 * @param f Fragment changing state
470 * @param context Context that the Fragment was attached to
471 */
472 public void onFragmentAttached(FragmentManager fm, Fragment f, Context context) {}
473
474 /**
Adam Powell10d69ac2017-04-25 15:24:49 -0700475 * Called right before the fragment's {@link Fragment#onCreate(Bundle)} method is called.
476 * This is a good time to inject any required dependencies or perform other configuration
477 * for the fragment.
478 *
479 * @param fm Host FragmentManager
480 * @param f Fragment changing state
481 * @param savedInstanceState Saved instance bundle from a previous instance
482 */
483 public void onFragmentPreCreated(FragmentManager fm, Fragment f,
484 Bundle savedInstanceState) {}
485
486 /**
Adam Powell38c67ff2016-10-28 10:24:40 -0700487 * Called after the fragment has returned from the FragmentManager's call to
488 * {@link Fragment#onCreate(Bundle)}. This will only happen once for any given
489 * fragment instance, though the fragment may be attached and detached multiple times.
490 *
491 * @param fm Host FragmentManager
492 * @param f Fragment changing state
493 * @param savedInstanceState Saved instance bundle from a previous instance
494 */
495 public void onFragmentCreated(FragmentManager fm, Fragment f, Bundle savedInstanceState) {}
496
497 /**
498 * Called after the fragment has returned from the FragmentManager's call to
499 * {@link Fragment#onActivityCreated(Bundle)}. This will only happen once for any given
500 * fragment instance, though the fragment may be attached and detached multiple times.
501 *
502 * @param fm Host FragmentManager
503 * @param f Fragment changing state
504 * @param savedInstanceState Saved instance bundle from a previous instance
505 */
506 public void onFragmentActivityCreated(FragmentManager fm, Fragment f,
507 Bundle savedInstanceState) {}
508
509 /**
510 * Called after the fragment has returned a non-null view from the FragmentManager's
511 * request to {@link Fragment#onCreateView(LayoutInflater, ViewGroup, Bundle)}.
512 *
513 * @param fm Host FragmentManager
514 * @param f Fragment that created and owns the view
515 * @param v View returned by the fragment
516 * @param savedInstanceState Saved instance bundle from a previous instance
517 */
518 public void onFragmentViewCreated(FragmentManager fm, Fragment f, View v,
519 Bundle savedInstanceState) {}
520
521 /**
522 * Called after the fragment has returned from the FragmentManager's call to
523 * {@link Fragment#onStart()}.
524 *
525 * @param fm Host FragmentManager
526 * @param f Fragment changing state
527 */
528 public void onFragmentStarted(FragmentManager fm, Fragment f) {}
529
530 /**
531 * Called after the fragment has returned from the FragmentManager's call to
532 * {@link Fragment#onResume()}.
533 *
534 * @param fm Host FragmentManager
535 * @param f Fragment changing state
536 */
537 public void onFragmentResumed(FragmentManager fm, Fragment f) {}
538
539 /**
540 * Called after the fragment has returned from the FragmentManager's call to
541 * {@link Fragment#onPause()}.
542 *
543 * @param fm Host FragmentManager
544 * @param f Fragment changing state
545 */
546 public void onFragmentPaused(FragmentManager fm, Fragment f) {}
547
548 /**
549 * Called after the fragment has returned from the FragmentManager's call to
550 * {@link Fragment#onStop()}.
551 *
552 * @param fm Host FragmentManager
553 * @param f Fragment changing state
554 */
555 public void onFragmentStopped(FragmentManager fm, Fragment f) {}
556
557 /**
558 * Called after the fragment has returned from the FragmentManager's call to
559 * {@link Fragment#onSaveInstanceState(Bundle)}.
560 *
561 * @param fm Host FragmentManager
562 * @param f Fragment changing state
563 * @param outState Saved state bundle for the fragment
564 */
565 public void onFragmentSaveInstanceState(FragmentManager fm, Fragment f, Bundle outState) {}
566
567 /**
568 * Called after the fragment has returned from the FragmentManager's call to
569 * {@link Fragment#onDestroyView()}.
570 *
571 * @param fm Host FragmentManager
572 * @param f Fragment changing state
573 */
574 public void onFragmentViewDestroyed(FragmentManager fm, Fragment f) {}
575
576 /**
577 * Called after the fragment has returned from the FragmentManager's call to
578 * {@link Fragment#onDestroy()}.
579 *
580 * @param fm Host FragmentManager
581 * @param f Fragment changing state
582 */
583 public void onFragmentDestroyed(FragmentManager fm, Fragment f) {}
584
585 /**
586 * Called after the fragment has returned from the FragmentManager's call to
587 * {@link Fragment#onDetach()}.
588 *
589 * @param fm Host FragmentManager
590 * @param f Fragment changing state
591 */
592 public void onFragmentDetached(FragmentManager fm, Fragment f) {}
593 }
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700594}
595
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700596final class FragmentManagerState implements Parcelable {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700597 FragmentState[] mActive;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700598 int[] mAdded;
599 BackStackState[] mBackStack;
Adam Powell5f3a05c2017-01-27 16:51:03 -0800600 int mPrimaryNavActiveIndex = -1;
George Mount838166d2017-03-23 14:23:29 -0700601 int mNextFragmentIndex;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700602
603 public FragmentManagerState() {
604 }
605
606 public FragmentManagerState(Parcel in) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700607 mActive = in.createTypedArray(FragmentState.CREATOR);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700608 mAdded = in.createIntArray();
609 mBackStack = in.createTypedArray(BackStackState.CREATOR);
Adam Powell5f3a05c2017-01-27 16:51:03 -0800610 mPrimaryNavActiveIndex = in.readInt();
George Mount838166d2017-03-23 14:23:29 -0700611 mNextFragmentIndex = in.readInt();
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700612 }
613
614 public int describeContents() {
615 return 0;
616 }
617
618 public void writeToParcel(Parcel dest, int flags) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -0700619 dest.writeTypedArray(mActive, flags);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700620 dest.writeIntArray(mAdded);
621 dest.writeTypedArray(mBackStack, flags);
Adam Powell5f3a05c2017-01-27 16:51:03 -0800622 dest.writeInt(mPrimaryNavActiveIndex);
George Mount838166d2017-03-23 14:23:29 -0700623 dest.writeInt(mNextFragmentIndex);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700624 }
625
Jeff Sharkey9e8f83d2019-02-28 12:06:45 -0700626 public static final @android.annotation.NonNull Parcelable.Creator<FragmentManagerState> CREATOR
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700627 = new Parcelable.Creator<FragmentManagerState>() {
628 public FragmentManagerState createFromParcel(Parcel in) {
629 return new FragmentManagerState(in);
630 }
631
632 public FragmentManagerState[] newArray(int size) {
633 return new FragmentManagerState[size];
634 }
635 };
Dianne Hackbornba51c3d2010-05-05 18:49:48 -0700636}
637
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700638/**
639 * Container for fragments associated with an activity.
640 */
Adam Powell371a8092014-06-20 12:51:12 -0700641final class FragmentManagerImpl extends FragmentManager implements LayoutInflater.Factory2 {
Craig Mautner1c437192012-08-01 10:01:16 -0700642 static boolean DEBUG = false;
Dianne Hackborn5ae74d62010-05-19 19:14:57 -0700643 static final String TAG = "FragmentManager";
644
Dianne Hackborndef15372010-08-15 12:43:52 -0700645 static final String TARGET_REQUEST_CODE_STATE_TAG = "android:target_req_state";
646 static final String TARGET_STATE_TAG = "android:target_state";
647 static final String VIEW_STATE_TAG = "android:view_state";
Adam Powell78fed9b2011-11-07 10:45:34 -0800648 static final String USER_VISIBLE_HINT_TAG = "android:user_visible_hint";
Dianne Hackborndef15372010-08-15 12:43:52 -0700649
Doris Liude9284d2015-05-22 15:41:46 -0700650 static class AnimateOnHWLayerIfNeededListener implements Animator.AnimatorListener {
651 private boolean mShouldRunOnHWLayer = false;
652 private View mView;
653 public AnimateOnHWLayerIfNeededListener(final View v) {
654 if (v == null) {
655 return;
656 }
657 mView = v;
658 }
659
660 @Override
661 public void onAnimationStart(Animator animation) {
662 mShouldRunOnHWLayer = shouldRunOnHWLayer(mView, animation);
663 if (mShouldRunOnHWLayer) {
664 mView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
665 }
666 }
667
668 @Override
669 public void onAnimationEnd(Animator animation) {
670 if (mShouldRunOnHWLayer) {
671 mView.setLayerType(View.LAYER_TYPE_NONE, null);
672 }
673 mView = null;
674 animation.removeListener(this);
675 }
676
677 @Override
678 public void onAnimationCancel(Animator animation) {
679
680 }
681
682 @Override
683 public void onAnimationRepeat(Animator animation) {
684
685 }
686 }
687
George Mounteca8e222016-07-07 13:13:05 -0700688 ArrayList<OpGenerator> mPendingActions;
Dianne Hackborn445646c2010-06-25 15:52:59 -0700689 boolean mExecutingActions;
George Mount838166d2017-03-23 14:23:29 -0700690
691 int mNextFragmentIndex = 0;
Mathew Inwood61e8ae62018-08-14 14:17:44 +0100692 @UnsupportedAppUsage
George Mount838166d2017-03-23 14:23:29 -0700693 SparseArray<Fragment> mActive;
Mathew Inwood61e8ae62018-08-14 14:17:44 +0100694 @UnsupportedAppUsage
George Mount7cdd49a2017-05-22 16:21:09 -0700695 final ArrayList<Fragment> mAdded = new ArrayList<>();
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700696 ArrayList<BackStackRecord> mBackStack;
Dianne Hackborn8eb2e242010-11-01 12:31:24 -0700697 ArrayList<Fragment> mCreatedMenus;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700698
Dianne Hackborndd913a52010-07-22 12:17:04 -0700699 // Must be accessed while locked.
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700700 ArrayList<BackStackRecord> mBackStackIndices;
Dianne Hackborndd913a52010-07-22 12:17:04 -0700701 ArrayList<Integer> mAvailBackStackIndices;
702
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700703 ArrayList<OnBackStackChangedListener> mBackStackChangeListeners;
Aurimas Liutikas8d5d55a2017-06-07 14:11:10 -0700704 final CopyOnWriteArrayList<Pair<FragmentLifecycleCallbacks, Boolean>>
705 mLifecycleCallbacks = new CopyOnWriteArrayList<>();
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700706
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700707 int mCurState = Fragment.INITIALIZING;
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700708 FragmentHostCallback<?> mHost;
Dianne Hackborn62bea2f2012-09-04 18:48:15 -0700709 FragmentContainer mContainer;
710 Fragment mParent;
Adam Powell5f3a05c2017-01-27 16:51:03 -0800711 Fragment mPrimaryNav;
Dianne Hackborn2dedce62010-04-15 14:45:25 -0700712
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -0700713 boolean mNeedMenuInvalidate;
Mathew Inwood61e8ae62018-08-14 14:17:44 +0100714 @UnsupportedAppUsage
Dianne Hackborn3e449ce2010-09-11 20:52:31 -0700715 boolean mStateSaved;
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800716 boolean mDestroyed;
Dianne Hackbornfb3cffe2010-10-25 17:08:56 -0700717 String mNoTransactionsBecause;
Adam Powell78fed9b2011-11-07 10:45:34 -0800718 boolean mHavePendingDeferredStart;
Adam Powell371a8092014-06-20 12:51:12 -0700719
George Mounta0ffaff2017-04-26 13:10:59 -0700720 // Temporary vars for removing redundant operations in BackStackRecords:
George Mounteca8e222016-07-07 13:13:05 -0700721 ArrayList<BackStackRecord> mTmpRecords;
722 ArrayList<Boolean> mTmpIsPop;
George Mounteca8e222016-07-07 13:13:05 -0700723 ArrayList<Fragment> mTmpAddedFragments;
724
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700725 // Temporary vars for state save and restore.
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -0700726 Bundle mStateBundle = null;
727 SparseArray<Parcelable> mStateArray = null;
George Mount86bfc662016-07-12 16:06:06 -0700728
729 // Postponed transactions.
730 ArrayList<StartEnterTransitionListener> mPostponedTransactions;
731
George Mountf1d88e62017-03-13 10:47:57 -0700732 // Prior to O, we allowed executing transactions during fragment manager state changes.
733 // This is dangerous, but we want to keep from breaking old applications.
734 boolean mAllowOldReentrantBehavior;
735
George Mountf804d6a2017-04-05 12:30:17 -0700736 // Saved FragmentManagerNonConfig during saveAllState() and cleared in noteStateNotSaved()
737 FragmentManagerNonConfig mSavedNonConfig;
738
Dianne Hackborn445646c2010-06-25 15:52:59 -0700739 Runnable mExecCommit = new Runnable() {
740 @Override
741 public void run() {
742 execPendingActions();
743 }
744 };
Dianne Hackborn625ac272010-09-17 18:29:22 -0700745
Dianne Hackborn4702a852012-08-17 15:18:29 -0700746 private void throwException(RuntimeException ex) {
747 Log.e(TAG, ex.getMessage());
748 LogWriter logw = new LogWriter(Log.ERROR, TAG);
Dianne Hackborn8c841092013-06-24 13:46:13 -0700749 PrintWriter pw = new FastPrintWriter(logw, false, 1024);
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700750 if (mHost != null) {
Dianne Hackborn4702a852012-08-17 15:18:29 -0700751 Log.e(TAG, "Activity state:");
Dianne Hackborn5bf6e1a2012-08-14 18:35:02 -0700752 try {
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700753 mHost.onDump(" ", null, pw, new String[] { });
Dianne Hackborn5bf6e1a2012-08-14 18:35:02 -0700754 } catch (Exception e) {
Dianne Hackborn8c841092013-06-24 13:46:13 -0700755 pw.flush();
Dianne Hackborn5bf6e1a2012-08-14 18:35:02 -0700756 Log.e(TAG, "Failed dumping state", e);
757 }
758 } else {
Dianne Hackborn4702a852012-08-17 15:18:29 -0700759 Log.e(TAG, "Fragment manager state:");
Dianne Hackborn5bf6e1a2012-08-14 18:35:02 -0700760 try {
Dianne Hackborn4702a852012-08-17 15:18:29 -0700761 dump(" ", null, pw, new String[] { });
Dianne Hackborn5bf6e1a2012-08-14 18:35:02 -0700762 } catch (Exception e) {
Dianne Hackborn8c841092013-06-24 13:46:13 -0700763 pw.flush();
Dianne Hackborn4702a852012-08-17 15:18:29 -0700764 Log.e(TAG, "Failed dumping state", e);
Dianne Hackborn5bf6e1a2012-08-14 18:35:02 -0700765 }
Dianne Hackborn5bf6e1a2012-08-14 18:35:02 -0700766 }
Dianne Hackborn8c841092013-06-24 13:46:13 -0700767 pw.flush();
Dianne Hackborn4702a852012-08-17 15:18:29 -0700768 throw ex;
Dianne Hackborn5bf6e1a2012-08-14 18:35:02 -0700769 }
770
Doris Liude9284d2015-05-22 15:41:46 -0700771 static boolean modifiesAlpha(Animator anim) {
772 if (anim == null) {
773 return false;
774 }
775 if (anim instanceof ValueAnimator) {
776 ValueAnimator valueAnim = (ValueAnimator) anim;
777 PropertyValuesHolder[] values = valueAnim.getValues();
778 for (int i = 0; i < values.length; i++) {
779 if (("alpha").equals(values[i].getPropertyName())) {
780 return true;
781 }
782 }
783 } else if (anim instanceof AnimatorSet) {
784 List<Animator> animList = ((AnimatorSet) anim).getChildAnimations();
785 for (int i = 0; i < animList.size(); i++) {
786 if (modifiesAlpha(animList.get(i))) {
787 return true;
788 }
789 }
790 }
791 return false;
792 }
793
794 static boolean shouldRunOnHWLayer(View v, Animator anim) {
795 if (v == null || anim == null) {
796 return false;
797 }
798 return v.getLayerType() == View.LAYER_TYPE_NONE
799 && v.hasOverlappingRendering()
800 && modifiesAlpha(anim);
801 }
802
803 /**
804 * Sets the to be animated view on hardware layer during the animation.
805 */
806 private void setHWLayerAnimListenerIfAlpha(final View v, Animator anim) {
807 if (v == null || anim == null) {
808 return;
809 }
810 if (shouldRunOnHWLayer(v, anim)) {
811 anim.addListener(new AnimateOnHWLayerIfNeededListener(v));
812 }
813 }
814
Dianne Hackborn625ac272010-09-17 18:29:22 -0700815 @Override
Dianne Hackborn48e7b452011-01-17 12:28:35 -0800816 public FragmentTransaction beginTransaction() {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700817 return new BackStackRecord(this);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700818 }
819
Dianne Hackborn625ac272010-09-17 18:29:22 -0700820 @Override
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800821 public boolean executePendingTransactions() {
George Mount86bfc662016-07-12 16:06:06 -0700822 boolean updates = execPendingActions();
823 forcePostponedTransactions();
824 return updates;
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800825 }
826
827 @Override
828 public void popBackStack() {
George Mounteca8e222016-07-07 13:13:05 -0700829 enqueueAction(new PopBackStackState(null, -1, 0), false);
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800830 }
831
832 @Override
833 public boolean popBackStackImmediate() {
834 checkStateLoss();
George Mounteca8e222016-07-07 13:13:05 -0700835 return popBackStackImmediate(null, -1, 0);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700836 }
837
Dianne Hackborn625ac272010-09-17 18:29:22 -0700838 @Override
George Mounteca8e222016-07-07 13:13:05 -0700839 public void popBackStack(String name, int flags) {
840 enqueueAction(new PopBackStackState(name, -1, flags), false);
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800841 }
842
843 @Override
844 public boolean popBackStackImmediate(String name, int flags) {
845 checkStateLoss();
George Mounteca8e222016-07-07 13:13:05 -0700846 return popBackStackImmediate(name, -1, flags);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700847 }
848
Dianne Hackborn625ac272010-09-17 18:29:22 -0700849 @Override
George Mounteca8e222016-07-07 13:13:05 -0700850 public void popBackStack(int id, int flags) {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800851 if (id < 0) {
852 throw new IllegalArgumentException("Bad id: " + id);
853 }
George Mounteca8e222016-07-07 13:13:05 -0700854 enqueueAction(new PopBackStackState(null, id, flags), false);
Dianne Hackborn3a57fb92010-11-15 17:58:52 -0800855 }
856
857 @Override
858 public boolean popBackStackImmediate(int id, int flags) {
859 checkStateLoss();
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700860 if (id < 0) {
861 throw new IllegalArgumentException("Bad id: " + id);
862 }
George Mounteca8e222016-07-07 13:13:05 -0700863 return popBackStackImmediate(null, id, flags);
864 }
865
866 /**
867 * Used by all public popBackStackImmediate methods, this executes pending transactions and
868 * returns true if the pop action did anything, regardless of what other pending
869 * transactions did.
870 *
871 * @return true if the pop operation did anything or false otherwise.
872 */
873 private boolean popBackStackImmediate(String name, int id, int flags) {
George Mount86bfc662016-07-12 16:06:06 -0700874 execPendingActions();
George Mounteca8e222016-07-07 13:13:05 -0700875 ensureExecReady(true);
876
Adam Powell5f3a05c2017-01-27 16:51:03 -0800877 if (mPrimaryNav != null // We have a primary nav fragment
878 && id < 0 // No valid id (since they're local)
879 && name == null) { // no name to pop to (since they're local)
880 final FragmentManager childManager = mPrimaryNav.mChildFragmentManager;
881 if (childManager != null && childManager.popBackStackImmediate()) {
882 // We did something, just not to this specific FragmentManager. Return true.
883 return true;
884 }
885 }
886
George Mounteca8e222016-07-07 13:13:05 -0700887 boolean executePop = popBackStackState(mTmpRecords, mTmpIsPop, name, id, flags);
888 if (executePop) {
889 mExecutingActions = true;
890 try {
George Mounta0ffaff2017-04-26 13:10:59 -0700891 removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
George Mounteca8e222016-07-07 13:13:05 -0700892 } finally {
893 cleanupExec();
894 }
895 }
896
897 doPendingDeferredStart();
George Mount838166d2017-03-23 14:23:29 -0700898 burpActive();
George Mounteca8e222016-07-07 13:13:05 -0700899 return executePop;
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700900 }
901
Dianne Hackborn625ac272010-09-17 18:29:22 -0700902 @Override
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800903 public int getBackStackEntryCount() {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700904 return mBackStack != null ? mBackStack.size() : 0;
905 }
906
Dianne Hackborn625ac272010-09-17 18:29:22 -0700907 @Override
Dianne Hackborn327fbd22011-01-17 14:38:50 -0800908 public BackStackEntry getBackStackEntryAt(int index) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700909 return mBackStack.get(index);
910 }
911
Dianne Hackborn625ac272010-09-17 18:29:22 -0700912 @Override
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700913 public void addOnBackStackChangedListener(OnBackStackChangedListener listener) {
914 if (mBackStackChangeListeners == null) {
915 mBackStackChangeListeners = new ArrayList<OnBackStackChangedListener>();
916 }
917 mBackStackChangeListeners.add(listener);
918 }
919
Dianne Hackborn625ac272010-09-17 18:29:22 -0700920 @Override
Dianne Hackbornc6669ca2010-09-16 01:33:24 -0700921 public void removeOnBackStackChangedListener(OnBackStackChangedListener listener) {
922 if (mBackStackChangeListeners != null) {
923 mBackStackChangeListeners.remove(listener);
924 }
925 }
926
Dianne Hackborn625ac272010-09-17 18:29:22 -0700927 @Override
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700928 public void putFragment(Bundle bundle, String key, Fragment fragment) {
929 if (fragment.mIndex < 0) {
Dianne Hackborn4702a852012-08-17 15:18:29 -0700930 throwException(new IllegalStateException("Fragment " + fragment
931 + " is not currently in the FragmentManager"));
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700932 }
933 bundle.putInt(key, fragment.mIndex);
934 }
935
Dianne Hackborn625ac272010-09-17 18:29:22 -0700936 @Override
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700937 public Fragment getFragment(Bundle bundle, String key) {
Dianne Hackborndef15372010-08-15 12:43:52 -0700938 int index = bundle.getInt(key, -1);
939 if (index == -1) {
940 return null;
941 }
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700942 Fragment f = mActive.get(index);
943 if (f == null) {
Cyril Mottier2de50822013-09-30 22:42:26 +0200944 throwException(new IllegalStateException("Fragment no longer exists for key "
Dianne Hackborn4702a852012-08-17 15:18:29 -0700945 + key + ": index " + index));
Dianne Hackbornb7a2e472010-08-12 16:20:42 -0700946 }
947 return f;
948 }
949
Dianne Hackborn625ac272010-09-17 18:29:22 -0700950 @Override
George Mounte196b6f2017-04-05 13:56:37 -0700951 public List<Fragment> getFragments() {
George Mount7cdd49a2017-05-22 16:21:09 -0700952 if (mAdded.isEmpty()) {
George Mountc7146be2017-03-29 14:13:03 +0000953 return Collections.EMPTY_LIST;
954 }
955 synchronized (mAdded) {
George Mounte196b6f2017-04-05 13:56:37 -0700956 return (List<Fragment>) mAdded.clone();
George Mountc7146be2017-03-29 14:13:03 +0000957 }
958 }
959
960 @Override
Dianne Hackbornb46ed762011-06-02 18:33:15 -0700961 public Fragment.SavedState saveFragmentInstanceState(Fragment fragment) {
962 if (fragment.mIndex < 0) {
Dianne Hackborn4702a852012-08-17 15:18:29 -0700963 throwException(new IllegalStateException("Fragment " + fragment
964 + " is not currently in the FragmentManager"));
Dianne Hackbornb46ed762011-06-02 18:33:15 -0700965 }
966 if (fragment.mState > Fragment.INITIALIZING) {
967 Bundle result = saveFragmentBasicState(fragment);
968 return result != null ? new Fragment.SavedState(result) : null;
969 }
970 return null;
971 }
972
973 @Override
Dianne Hackborn6d9dcbc2012-10-02 17:51:13 -0700974 public boolean isDestroyed() {
975 return mDestroyed;
976 }
977
978 @Override
Dianne Hackborna2ea7472010-12-20 12:10:01 -0800979 public String toString() {
980 StringBuilder sb = new StringBuilder(128);
981 sb.append("FragmentManager{");
982 sb.append(Integer.toHexString(System.identityHashCode(this)));
983 sb.append(" in ");
Dianne Hackborn62bea2f2012-09-04 18:48:15 -0700984 if (mParent != null) {
985 DebugUtils.buildShortClassTag(mParent, sb);
986 } else {
Todd Kennedya5fc6f02015-04-14 18:22:54 -0700987 DebugUtils.buildShortClassTag(mHost, sb);
Dianne Hackborn62bea2f2012-09-04 18:48:15 -0700988 }
Dianne Hackborna2ea7472010-12-20 12:10:01 -0800989 sb.append("}}");
990 return sb.toString();
991 }
992
993 @Override
Dianne Hackborn625ac272010-09-17 18:29:22 -0700994 public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
Dianne Hackborn625ac272010-09-17 18:29:22 -0700995 String innerPrefix = prefix + " ";
996
Dianne Hackbornd173fa32010-12-23 13:58:22 -0800997 int N;
998 if (mActive != null) {
999 N = mActive.size();
1000 if (N > 0) {
1001 writer.print(prefix); writer.print("Active Fragments in ");
1002 writer.print(Integer.toHexString(System.identityHashCode(this)));
1003 writer.println(":");
1004 for (int i=0; i<N; i++) {
George Mount838166d2017-03-23 14:23:29 -07001005 Fragment f = mActive.valueAt(i);
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001006 writer.print(prefix); writer.print(" #"); writer.print(i);
1007 writer.print(": "); writer.println(f);
1008 if (f != null) {
1009 f.dump(innerPrefix, fd, writer, args);
1010 }
1011 }
Dianne Hackborn625ac272010-09-17 18:29:22 -07001012 }
1013 }
1014
George Mount7cdd49a2017-05-22 16:21:09 -07001015 N = mAdded.size();
1016 if (N > 0) {
1017 writer.print(prefix);
1018 writer.println("Added Fragments:");
1019 for (int i = 0; i < N; i++) {
1020 Fragment f = mAdded.get(i);
1021 writer.print(prefix);
1022 writer.print(" #");
1023 writer.print(i);
1024 writer.print(": ");
1025 writer.println(f.toString());
Dianne Hackborn625ac272010-09-17 18:29:22 -07001026 }
1027 }
1028
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001029 if (mCreatedMenus != null) {
1030 N = mCreatedMenus.size();
1031 if (N > 0) {
1032 writer.print(prefix); writer.println("Fragments Created Menus:");
1033 for (int i=0; i<N; i++) {
1034 Fragment f = mCreatedMenus.get(i);
1035 writer.print(prefix); writer.print(" #"); writer.print(i);
1036 writer.print(": "); writer.println(f.toString());
1037 }
1038 }
1039 }
1040
Dianne Hackborn625ac272010-09-17 18:29:22 -07001041 if (mBackStack != null) {
1042 N = mBackStack.size();
1043 if (N > 0) {
1044 writer.print(prefix); writer.println("Back Stack:");
1045 for (int i=0; i<N; i++) {
1046 BackStackRecord bs = mBackStack.get(i);
1047 writer.print(prefix); writer.print(" #"); writer.print(i);
1048 writer.print(": "); writer.println(bs.toString());
Dianne Hackborn30d71892010-12-11 10:37:55 -08001049 bs.dump(innerPrefix, fd, writer, args);
Dianne Hackborn625ac272010-09-17 18:29:22 -07001050 }
1051 }
1052 }
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001053
1054 synchronized (this) {
1055 if (mBackStackIndices != null) {
1056 N = mBackStackIndices.size();
1057 if (N > 0) {
1058 writer.print(prefix); writer.println("Back Stack Indices:");
1059 for (int i=0; i<N; i++) {
1060 BackStackRecord bs = mBackStackIndices.get(i);
1061 writer.print(prefix); writer.print(" #"); writer.print(i);
1062 writer.print(": "); writer.println(bs);
1063 }
1064 }
1065 }
1066
1067 if (mAvailBackStackIndices != null && mAvailBackStackIndices.size() > 0) {
1068 writer.print(prefix); writer.print("mAvailBackStackIndices: ");
1069 writer.println(Arrays.toString(mAvailBackStackIndices.toArray()));
1070 }
1071 }
1072
1073 if (mPendingActions != null) {
1074 N = mPendingActions.size();
1075 if (N > 0) {
1076 writer.print(prefix); writer.println("Pending Actions:");
1077 for (int i=0; i<N; i++) {
George Mounteca8e222016-07-07 13:13:05 -07001078 OpGenerator r = mPendingActions.get(i);
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001079 writer.print(prefix); writer.print(" #"); writer.print(i);
1080 writer.print(": "); writer.println(r);
1081 }
1082 }
1083 }
1084
1085 writer.print(prefix); writer.println("FragmentManager misc state:");
Todd Kennedya5fc6f02015-04-14 18:22:54 -07001086 writer.print(prefix); writer.print(" mHost="); writer.println(mHost);
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001087 writer.print(prefix); writer.print(" mContainer="); writer.println(mContainer);
1088 if (mParent != null) {
1089 writer.print(prefix); writer.print(" mParent="); writer.println(mParent);
1090 }
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001091 writer.print(prefix); writer.print(" mCurState="); writer.print(mCurState);
1092 writer.print(" mStateSaved="); writer.print(mStateSaved);
1093 writer.print(" mDestroyed="); writer.println(mDestroyed);
1094 if (mNeedMenuInvalidate) {
1095 writer.print(prefix); writer.print(" mNeedMenuInvalidate=");
1096 writer.println(mNeedMenuInvalidate);
1097 }
1098 if (mNoTransactionsBecause != null) {
1099 writer.print(prefix); writer.print(" mNoTransactionsBecause=");
1100 writer.println(mNoTransactionsBecause);
1101 }
Dianne Hackborn625ac272010-09-17 18:29:22 -07001102 }
1103
Mathew Inwood61e8ae62018-08-14 14:17:44 +01001104 @UnsupportedAppUsage
Chet Haasea18a86b2010-09-07 13:20:00 -07001105 Animator loadAnimator(Fragment fragment, int transit, boolean enter,
Dianne Hackbornf121be72010-05-06 14:10:32 -07001106 int transitionStyle) {
George Mount86bfc662016-07-12 16:06:06 -07001107 Animator animObj = fragment.onCreateAnimator(transit, enter, fragment.getNextAnim());
Dianne Hackbornf121be72010-05-06 14:10:32 -07001108 if (animObj != null) {
1109 return animObj;
1110 }
1111
George Mount86bfc662016-07-12 16:06:06 -07001112 if (fragment.getNextAnim() != 0) {
1113 Animator anim = AnimatorInflater.loadAnimator(mHost.getContext(),
1114 fragment.getNextAnim());
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001115 if (anim != null) {
1116 return anim;
1117 }
1118 }
1119
Dianne Hackbornf121be72010-05-06 14:10:32 -07001120 if (transit == 0) {
1121 return null;
1122 }
1123
1124 int styleIndex = transitToStyleIndex(transit, enter);
1125 if (styleIndex < 0) {
1126 return null;
1127 }
1128
Todd Kennedya5fc6f02015-04-14 18:22:54 -07001129 if (transitionStyle == 0 && mHost.onHasWindowAnimations()) {
1130 transitionStyle = mHost.onGetWindowAnimations();
Dianne Hackbornf121be72010-05-06 14:10:32 -07001131 }
1132 if (transitionStyle == 0) {
1133 return null;
1134 }
1135
Todd Kennedya5fc6f02015-04-14 18:22:54 -07001136 TypedArray attrs = mHost.getContext().obtainStyledAttributes(transitionStyle,
Chet Haase811ed1062010-08-06 10:38:15 -07001137 com.android.internal.R.styleable.FragmentAnimation);
Dianne Hackbornf121be72010-05-06 14:10:32 -07001138 int anim = attrs.getResourceId(styleIndex, 0);
1139 attrs.recycle();
1140
1141 if (anim == 0) {
1142 return null;
1143 }
1144
Todd Kennedya5fc6f02015-04-14 18:22:54 -07001145 return AnimatorInflater.loadAnimator(mHost.getContext(), anim);
Dianne Hackbornf121be72010-05-06 14:10:32 -07001146 }
1147
Adam Powell635c60a2011-10-26 10:22:16 -07001148 public void performPendingDeferredStart(Fragment f) {
1149 if (f.mDeferStart) {
Adam Powell78fed9b2011-11-07 10:45:34 -08001150 if (mExecutingActions) {
1151 // Wait until we're done executing our pending transactions
1152 mHavePendingDeferredStart = true;
1153 return;
1154 }
Adam Powell635c60a2011-10-26 10:22:16 -07001155 f.mDeferStart = false;
Dianne Hackbornee76efb2012-06-05 10:27:40 -07001156 moveToState(f, mCurState, 0, 0, false);
Adam Powell635c60a2011-10-26 10:22:16 -07001157 }
1158 }
1159
Adam Powell467cc6f2016-05-11 13:45:33 -07001160 boolean isStateAtLeast(int state) {
1161 return mCurState >= state;
1162 }
1163
Aurimas Liutikas221f15d42017-03-30 16:32:58 -07001164 @SuppressWarnings("ReferenceEquality")
Dianne Hackbornee76efb2012-06-05 10:27:40 -07001165 void moveToState(Fragment f, int newState, int transit, int transitionStyle,
1166 boolean keepActive) {
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07001167 if (DEBUG && false) Log.v(TAG, "moveToState: " + f
1168 + " oldState=" + f.mState + " newState=" + newState
1169 + " mRemoving=" + f.mRemoving + " Callers=" + Debug.getCallers(5));
Craig Mautner1c437192012-08-01 10:01:16 -07001170
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001171 // Fragments that are not currently added will sit in the onCreate() state.
Dianne Hackborne181bd92012-09-25 14:15:15 -07001172 if ((!f.mAdded || f.mDetached) && newState > Fragment.CREATED) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001173 newState = Fragment.CREATED;
1174 }
Dianne Hackbornf9302322011-06-14 18:36:14 -07001175 if (f.mRemoving && newState > f.mState) {
George Mount5daf06c2017-04-03 15:36:01 -07001176 if (f.mState == Fragment.INITIALIZING && f.isInBackStack()) {
1177 // Allow the fragment to be created so that it can be saved later.
1178 newState = Fragment.CREATED;
1179 } else {
1180 // While removing a fragment, we can't change it to a higher state.
1181 newState = f.mState;
1182 }
Dianne Hackbornf9302322011-06-14 18:36:14 -07001183 }
Adam Powell2db4e4b2011-11-02 14:30:47 -07001184 // Defer start if requested; don't allow it to move to STARTED or higher
1185 // if it's not already started.
1186 if (f.mDeferStart && f.mState < Fragment.STARTED && newState > Fragment.STOPPED) {
Adam Powell635c60a2011-10-26 10:22:16 -07001187 newState = Fragment.STOPPED;
1188 }
Adam Powellbb3aa342016-11-16 10:34:57 -08001189 if (f.mState <= newState) {
Dianne Hackborne3a7f622011-03-03 21:48:24 -08001190 // For fragments that are created from a layout, when restoring from
1191 // state we don't want to allow them to be created until they are
1192 // being reloaded from the layout.
1193 if (f.mFromLayout && !f.mInLayout) {
1194 return;
1195 }
George Mount86bfc662016-07-12 16:06:06 -07001196 if (f.getAnimatingAway() != null) {
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001197 // The fragment is currently being animated... but! Now we
1198 // want to move our state back up. Give up on waiting for the
1199 // animation, move to whatever the final state should be once
1200 // the animation is done, and then we can proceed from there.
George Mount86bfc662016-07-12 16:06:06 -07001201 f.setAnimatingAway(null);
1202 moveToState(f, f.getStateAfterAnimating(), 0, 0, true);
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001203 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001204 switch (f.mState) {
1205 case Fragment.INITIALIZING:
Adam Powellbb3aa342016-11-16 10:34:57 -08001206 if (newState > Fragment.INITIALIZING) {
1207 if (DEBUG) Log.v(TAG, "moveto CREATED: " + f);
1208 if (f.mSavedFragmentState != null) {
1209 f.mSavedViewState = f.mSavedFragmentState.getSparseParcelableArray(
1210 FragmentManagerImpl.VIEW_STATE_TAG);
1211 f.mTarget = getFragment(f.mSavedFragmentState,
1212 FragmentManagerImpl.TARGET_STATE_TAG);
1213 if (f.mTarget != null) {
1214 f.mTargetRequestCode = f.mSavedFragmentState.getInt(
1215 FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG, 0);
1216 }
1217 f.mUserVisibleHint = f.mSavedFragmentState.getBoolean(
1218 FragmentManagerImpl.USER_VISIBLE_HINT_TAG, true);
1219 if (!f.mUserVisibleHint) {
1220 f.mDeferStart = true;
1221 if (newState > Fragment.STOPPED) {
1222 newState = Fragment.STOPPED;
1223 }
Adam Powell78fed9b2011-11-07 10:45:34 -08001224 }
1225 }
Adam Powellab209a62017-01-26 14:14:34 -08001226
Adam Powellbb3aa342016-11-16 10:34:57 -08001227 f.mHost = mHost;
1228 f.mParentFragment = mParent;
1229 f.mFragmentManager = mParent != null
1230 ? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();
Adam Powellab209a62017-01-26 14:14:34 -08001231
1232 // If we have a target fragment, push it along to at least CREATED
1233 // so that this one can rely on it as an initialized dependency.
1234 if (f.mTarget != null) {
George Mount838166d2017-03-23 14:23:29 -07001235 if (mActive.get(f.mTarget.mIndex) != f.mTarget) {
Adam Powellab209a62017-01-26 14:14:34 -08001236 throw new IllegalStateException("Fragment " + f
1237 + " declared target fragment " + f.mTarget
1238 + " that does not belong to this FragmentManager!");
1239 }
1240 if (f.mTarget.mState < Fragment.CREATED) {
1241 moveToState(f.mTarget, Fragment.CREATED, 0, 0, true);
1242 }
1243 }
1244
Adam Powellbb3aa342016-11-16 10:34:57 -08001245 dispatchOnFragmentPreAttached(f, mHost.getContext(), false);
1246 f.mCalled = false;
1247 f.onAttach(mHost.getContext());
1248 if (!f.mCalled) {
1249 throw new SuperNotCalledException("Fragment " + f
1250 + " did not call through to super.onAttach()");
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001251 }
Adam Powellbb3aa342016-11-16 10:34:57 -08001252 if (f.mParentFragment == null) {
1253 mHost.onAttachFragment(f);
1254 } else {
1255 f.mParentFragment.onAttachFragment(f);
1256 }
1257 dispatchOnFragmentAttached(f, mHost.getContext(), false);
1258
George Mount15c21ff2017-07-19 10:47:48 -07001259 if (!f.mIsCreated) {
Adam Powell10d69ac2017-04-25 15:24:49 -07001260 dispatchOnFragmentPreCreated(f, f.mSavedFragmentState, false);
Adam Powellbb3aa342016-11-16 10:34:57 -08001261 f.performCreate(f.mSavedFragmentState);
1262 dispatchOnFragmentCreated(f, f.mSavedFragmentState, false);
1263 } else {
1264 f.restoreChildFragmentState(f.mSavedFragmentState, true);
1265 f.mState = Fragment.CREATED;
1266 }
1267 f.mRetaining = false;
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001268 }
Aurimas Liutikas221f15d42017-03-30 16:32:58 -07001269 // fall through
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001270 case Fragment.CREATED:
Adam Powellbb3aa342016-11-16 10:34:57 -08001271 // This is outside the if statement below on purpose; we want this to run
1272 // even if we do a moveToState from CREATED => *, CREATED => CREATED, and
1273 // * => CREATED as part of the case fallthrough above.
1274 ensureInflatedFragmentView(f);
1275
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001276 if (newState > Fragment.CREATED) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001277 if (DEBUG) Log.v(TAG, "moveto ACTIVITY_CREATED: " + f);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001278 if (!f.mFromLayout) {
1279 ViewGroup container = null;
1280 if (f.mContainerId != 0) {
Adam Powelle01f5952016-02-23 15:25:42 -08001281 if (f.mContainerId == View.NO_ID) {
1282 throwException(new IllegalArgumentException(
1283 "Cannot create fragment "
1284 + f
1285 + " for a container view with no id"));
1286 }
Alan Viverette04fd4702017-04-13 16:37:06 -04001287 container = mContainer.onFindViewById(f.mContainerId);
Dianne Hackborn352cc982011-01-04 11:34:18 -08001288 if (container == null && !f.mRestored) {
Adam Powelle01f5952016-02-23 15:25:42 -08001289 String resName;
1290 try {
1291 resName = f.getResources().getResourceName(f.mContainerId);
1292 } catch (NotFoundException e) {
1293 resName = "unknown";
1294 }
Dianne Hackborn4702a852012-08-17 15:18:29 -07001295 throwException(new IllegalArgumentException(
1296 "No view found for id 0x"
1297 + Integer.toHexString(f.mContainerId) + " ("
Adam Powelle01f5952016-02-23 15:25:42 -08001298 + resName
Dianne Hackborn4702a852012-08-17 15:18:29 -07001299 + ") for fragment " + f));
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001300 }
1301 }
1302 f.mContainer = container;
George Mount3fd81292017-04-17 16:50:26 -07001303 f.mView = f.performCreateView(f.performGetLayoutInflater(
Dianne Hackborn1b8ecc52012-09-08 17:03:52 -07001304 f.mSavedFragmentState), container, f.mSavedFragmentState);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001305 if (f.mView != null) {
1306 f.mView.setSaveFromParentEnabled(false);
1307 if (container != null) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001308 container.addView(f.mView);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001309 }
George Mount86bfc662016-07-12 16:06:06 -07001310 if (f.mHidden) {
1311 f.mView.setVisibility(View.GONE);
George Mount86bfc662016-07-12 16:06:06 -07001312 }
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001313 f.onViewCreated(f.mView, f.mSavedFragmentState);
Adam Powell38c67ff2016-10-28 10:24:40 -07001314 dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState,
1315 false);
George Mount0c3ab752016-11-29 11:36:17 -08001316 // Only animate the view if it is visible. This is done after
1317 // dispatchOnFragmentViewCreated in case visibility is changed
1318 f.mIsNewlyAdded = (f.mView.getVisibility() == View.VISIBLE)
1319 && f.mContainer != null;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001320 }
1321 }
Dianne Hackborn1b8ecc52012-09-08 17:03:52 -07001322
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001323 f.performActivityCreated(f.mSavedFragmentState);
Adam Powell38c67ff2016-10-28 10:24:40 -07001324 dispatchOnFragmentActivityCreated(f, f.mSavedFragmentState, false);
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001325 if (f.mView != null) {
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001326 f.restoreViewState(f.mSavedFragmentState);
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001327 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001328 f.mSavedFragmentState = null;
1329 }
Aurimas Liutikas221f15d42017-03-30 16:32:58 -07001330 // fall through
Dianne Hackbornc8017682010-07-06 13:34:38 -07001331 case Fragment.ACTIVITY_CREATED:
Adam Powelleacacb52016-03-23 13:07:27 -07001332 if (newState > Fragment.ACTIVITY_CREATED) {
1333 f.mState = Fragment.STOPPED;
1334 }
Aurimas Liutikas221f15d42017-03-30 16:32:58 -07001335 // fall through
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001336 case Fragment.STOPPED:
1337 if (newState > Fragment.STOPPED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001338 if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
Dianne Hackbornafc4b282011-06-10 17:03:42 -07001339 f.performStart();
Adam Powell38c67ff2016-10-28 10:24:40 -07001340 dispatchOnFragmentStarted(f, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001341 }
Aurimas Liutikas221f15d42017-03-30 16:32:58 -07001342 // fall through
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001343 case Fragment.STARTED:
1344 if (newState > Fragment.STARTED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001345 if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001346 f.performResume();
Adam Powell38c67ff2016-10-28 10:24:40 -07001347 dispatchOnFragmentResumed(f, false);
Adam Powell95202512011-08-07 17:20:17 -07001348 // Get rid of this in case we saved it and never needed it.
1349 f.mSavedFragmentState = null;
1350 f.mSavedViewState = null;
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001351 }
1352 }
1353 } else if (f.mState > newState) {
1354 switch (f.mState) {
1355 case Fragment.RESUMED:
1356 if (newState < Fragment.RESUMED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001357 if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f);
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001358 f.performPause();
Adam Powell38c67ff2016-10-28 10:24:40 -07001359 dispatchOnFragmentPaused(f, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001360 }
Aurimas Liutikas221f15d42017-03-30 16:32:58 -07001361 // fall through
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001362 case Fragment.STARTED:
1363 if (newState < Fragment.STARTED) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001364 if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f);
Dianne Hackborn2707d602010-07-09 18:01:20 -07001365 f.performStop();
Adam Powell38c67ff2016-10-28 10:24:40 -07001366 dispatchOnFragmentStopped(f, false);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001367 }
Aurimas Liutikas221f15d42017-03-30 16:32:58 -07001368 // fall through
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001369 case Fragment.STOPPED:
Dianne Hackbornc8017682010-07-06 13:34:38 -07001370 case Fragment.ACTIVITY_CREATED:
1371 if (newState < Fragment.ACTIVITY_CREATED) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001372 if (DEBUG) Log.v(TAG, "movefrom ACTIVITY_CREATED: " + f);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001373 if (f.mView != null) {
1374 // Need to save the current view state if not
1375 // done already.
Todd Kennedy46d168f2015-05-13 11:13:58 -07001376 if (mHost.onShouldSaveFragmentState(f) && f.mSavedViewState == null) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001377 saveFragmentViewState(f);
Dianne Hackbornf121be72010-05-06 14:10:32 -07001378 }
Dianne Hackborndef15372010-08-15 12:43:52 -07001379 }
Dianne Hackbornafc4b282011-06-10 17:03:42 -07001380 f.performDestroyView();
Adam Powell38c67ff2016-10-28 10:24:40 -07001381 dispatchOnFragmentViewDestroyed(f, false);
Dianne Hackborndef15372010-08-15 12:43:52 -07001382 if (f.mView != null && f.mContainer != null) {
George Mountd1cfbc52017-06-08 14:18:31 -07001383 if (getTargetSdk() >= Build.VERSION_CODES.O) {
1384 // Stop any current animations:
1385 f.mView.clearAnimation();
1386 f.mContainer.endViewTransition(f.mView);
1387 }
Chet Haaseb20db3e2010-09-10 13:07:30 -07001388 Animator anim = null;
George Mountc21dfd92017-01-05 16:50:25 -08001389 if (mCurState > Fragment.INITIALIZING && !mDestroyed
1390 && f.mView.getVisibility() == View.VISIBLE
1391 && f.mView.getTransitionAlpha() > 0) {
Chet Haaseb20db3e2010-09-10 13:07:30 -07001392 anim = loadAnimator(f, transit, false,
Dianne Hackborndef15372010-08-15 12:43:52 -07001393 transitionStyle);
Chet Haaseb20db3e2010-09-10 13:07:30 -07001394 }
George Mountc21dfd92017-01-05 16:50:25 -08001395 f.mView.setTransitionAlpha(1f);
Chet Haaseb20db3e2010-09-10 13:07:30 -07001396 if (anim != null) {
1397 final ViewGroup container = f.mContainer;
1398 final View view = f.mView;
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001399 final Fragment fragment = f;
Chet Haaseb20db3e2010-09-10 13:07:30 -07001400 container.startViewTransition(view);
George Mount86bfc662016-07-12 16:06:06 -07001401 f.setAnimatingAway(anim);
1402 f.setStateAfterAnimating(newState);
Chet Haaseb20db3e2010-09-10 13:07:30 -07001403 anim.addListener(new AnimatorListenerAdapter() {
1404 @Override
1405 public void onAnimationEnd(Animator anim) {
1406 container.endViewTransition(view);
George Mount3ceb1162017-09-11 11:01:51 -07001407 Animator animator = f.getAnimatingAway();
1408 f.setAnimatingAway(null);
1409 // If the animation finished immediately, the fragment's
1410 // view will still be there. If so, we can just pretend
1411 // there was no animation and skip the moveToState()
1412 if (container.indexOfChild(view) == -1
1413 && animator != null) {
George Mount86bfc662016-07-12 16:06:06 -07001414 moveToState(fragment, fragment.getStateAfterAnimating(),
Dianne Hackbornee76efb2012-06-05 10:27:40 -07001415 0, 0, false);
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001416 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001417 }
Chet Haaseb20db3e2010-09-10 13:07:30 -07001418 });
1419 anim.setTarget(f.mView);
Doris Liude9284d2015-05-22 15:41:46 -07001420 setHWLayerAnimListenerIfAlpha(f.mView, anim);
Chet Haaseb20db3e2010-09-10 13:07:30 -07001421 anim.start();
1422
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001423 }
Dianne Hackborndef15372010-08-15 12:43:52 -07001424 f.mContainer.removeView(f.mView);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001425 }
1426 f.mContainer = null;
1427 f.mView = null;
Adam Powellbb3aa342016-11-16 10:34:57 -08001428 f.mInLayout = false;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001429 }
Aurimas Liutikas221f15d42017-03-30 16:32:58 -07001430 // fall through
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001431 case Fragment.CREATED:
1432 if (newState < Fragment.CREATED) {
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001433 if (mDestroyed) {
George Mount86bfc662016-07-12 16:06:06 -07001434 if (f.getAnimatingAway() != null) {
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001435 // The fragment's containing activity is
1436 // being destroyed, but this fragment is
1437 // currently animating away. Stop the
1438 // animation right now -- it is not needed,
1439 // and we can't wait any more on destroying
1440 // the fragment.
George Mount86bfc662016-07-12 16:06:06 -07001441 Animator anim = f.getAnimatingAway();
1442 f.setAnimatingAway(null);
Dianne Hackborn1b39e222010-12-28 14:17:18 -08001443 anim.cancel();
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001444 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001445 }
George Mount86bfc662016-07-12 16:06:06 -07001446 if (f.getAnimatingAway() != null) {
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001447 // We are waiting for the fragment's view to finish
1448 // animating away. Just make a note of the state
1449 // the fragment now should move to once the animation
1450 // is done.
George Mount86bfc662016-07-12 16:06:06 -07001451 f.setStateAfterAnimating(newState);
Dianne Hackbornf9302322011-06-14 18:36:14 -07001452 newState = Fragment.CREATED;
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001453 } else {
1454 if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f);
1455 if (!f.mRetaining) {
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001456 f.performDestroy();
Adam Powell38c67ff2016-10-28 10:24:40 -07001457 dispatchOnFragmentDestroyed(f, false);
Adam Powelld1d4d9c2016-01-12 10:11:42 -08001458 } else {
Adam Powellcbade7f2016-04-15 11:14:37 -07001459 f.mState = Fragment.INITIALIZING;
Dianne Hackbornd173fa32010-12-23 13:58:22 -08001460 }
1461
Adam Powella9bab982016-04-21 11:04:41 -07001462 f.performDetach();
Adam Powell38c67ff2016-10-28 10:24:40 -07001463 dispatchOnFragmentDetached(f, false);
Dianne Hackbornee76efb2012-06-05 10:27:40 -07001464 if (!keepActive) {
1465 if (!f.mRetaining) {
1466 makeInactive(f);
1467 } else {
Todd Kennedya5fc6f02015-04-14 18:22:54 -07001468 f.mHost = null;
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001469 f.mParentFragment = null;
Dianne Hackbornee76efb2012-06-05 10:27:40 -07001470 f.mFragmentManager = null;
1471 }
Dianne Hackbornf9302322011-06-14 18:36:14 -07001472 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001473 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001474 }
1475 }
1476 }
1477
Adam Powelld1d4d9c2016-01-12 10:11:42 -08001478 if (f.mState != newState) {
1479 Log.w(TAG, "moveToState: Fragment state for " + f + " not updated inline; "
1480 + "expected state " + newState + " found " + f.mState);
1481 f.mState = newState;
1482 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001483 }
1484
Dianne Hackborn625ac272010-09-17 18:29:22 -07001485 void moveToState(Fragment f) {
Dianne Hackbornee76efb2012-06-05 10:27:40 -07001486 moveToState(f, mCurState, 0, 0, false);
Dianne Hackborn625ac272010-09-17 18:29:22 -07001487 }
1488
Adam Powellbb3aa342016-11-16 10:34:57 -08001489 void ensureInflatedFragmentView(Fragment f) {
1490 if (f.mFromLayout && !f.mPerformedCreateView) {
George Mount3fd81292017-04-17 16:50:26 -07001491 f.mView = f.performCreateView(f.performGetLayoutInflater(
Adam Powellbb3aa342016-11-16 10:34:57 -08001492 f.mSavedFragmentState), null, f.mSavedFragmentState);
1493 if (f.mView != null) {
1494 f.mView.setSaveFromParentEnabled(false);
1495 if (f.mHidden) f.mView.setVisibility(View.GONE);
1496 f.onViewCreated(f.mView, f.mSavedFragmentState);
1497 dispatchOnFragmentViewCreated(f, f.mView, f.mSavedFragmentState, false);
1498 }
1499 }
1500 }
1501
George Mounteca8e222016-07-07 13:13:05 -07001502 /**
1503 * Fragments that have been shown or hidden don't have their visibility changed or
1504 * animations run during the {@link #showFragment(Fragment)} or {@link #hideFragment(Fragment)}
1505 * calls. After fragments are brought to their final state in
1506 * {@link #moveFragmentToExpectedState(Fragment)} the fragments that have been shown or
1507 * hidden must have their visibility changed and their animations started here.
1508 *
1509 * @param fragment The fragment with mHiddenChanged = true that should change its View's
1510 * visibility and start the show or hide animation.
1511 */
1512 void completeShowHideFragment(final Fragment fragment) {
1513 if (fragment.mView != null) {
George Mount86bfc662016-07-12 16:06:06 -07001514 Animator anim = loadAnimator(fragment, fragment.getNextTransition(), !fragment.mHidden,
1515 fragment.getNextTransitionStyle());
George Mounteca8e222016-07-07 13:13:05 -07001516 if (anim != null) {
1517 anim.setTarget(fragment.mView);
1518 if (fragment.mHidden) {
George Mount4fe47112016-10-27 08:12:36 -07001519 if (fragment.isHideReplaced()) {
1520 fragment.setHideReplaced(false);
1521 } else {
George Mountc5828b52017-04-19 07:29:45 -07001522 final ViewGroup container = fragment.mContainer;
1523 final View animatingView = fragment.mView;
George Mount416b3772017-04-20 13:16:52 -07001524 if (container != null) {
1525 container.startViewTransition(animatingView);
1526 }
George Mount4fe47112016-10-27 08:12:36 -07001527 // Delay the actual hide operation until the animation finishes, otherwise
1528 // the fragment will just immediately disappear
1529 anim.addListener(new AnimatorListenerAdapter() {
1530 @Override
1531 public void onAnimationEnd(Animator animation) {
George Mount416b3772017-04-20 13:16:52 -07001532 if (container != null) {
1533 container.endViewTransition(animatingView);
1534 }
George Mount4fe47112016-10-27 08:12:36 -07001535 animation.removeListener(this);
George Mountc5828b52017-04-19 07:29:45 -07001536 animatingView.setVisibility(View.GONE);
George Mounteca8e222016-07-07 13:13:05 -07001537 }
George Mount4fe47112016-10-27 08:12:36 -07001538 });
1539 }
George Mountc5828b52017-04-19 07:29:45 -07001540 } else {
1541 fragment.mView.setVisibility(View.VISIBLE);
George Mounteca8e222016-07-07 13:13:05 -07001542 }
1543 setHWLayerAnimListenerIfAlpha(fragment.mView, anim);
1544 anim.start();
1545 } else {
George Mount4fe47112016-10-27 08:12:36 -07001546 final int visibility = fragment.mHidden && !fragment.isHideReplaced()
1547 ? View.GONE
1548 : View.VISIBLE;
George Mounteca8e222016-07-07 13:13:05 -07001549 fragment.mView.setVisibility(visibility);
George Mount4fe47112016-10-27 08:12:36 -07001550 if (fragment.isHideReplaced()) {
1551 fragment.setHideReplaced(false);
1552 }
George Mounteca8e222016-07-07 13:13:05 -07001553 }
1554 }
1555 if (fragment.mAdded && fragment.mHasMenu && fragment.mMenuVisible) {
1556 mNeedMenuInvalidate = true;
1557 }
1558 fragment.mHiddenChanged = false;
1559 fragment.onHiddenChanged(fragment.mHidden);
Dianne Hackbornf121be72010-05-06 14:10:32 -07001560 }
George Mounteca8e222016-07-07 13:13:05 -07001561
1562 /**
1563 * Moves a fragment to its expected final state or the fragment manager's state, depending
1564 * on whether the fragment manager's state is raised properly.
1565 *
1566 * @param f The fragment to change.
1567 */
George Mount86bfc662016-07-12 16:06:06 -07001568 void moveFragmentToExpectedState(final Fragment f) {
George Mounteca8e222016-07-07 13:13:05 -07001569 if (f == null) {
1570 return;
1571 }
1572 int nextState = mCurState;
1573 if (f.mRemoving) {
1574 if (f.isInBackStack()) {
George Mount851179d2016-10-27 14:22:27 -07001575 nextState = Math.min(nextState, Fragment.CREATED);
George Mounteca8e222016-07-07 13:13:05 -07001576 } else {
George Mount851179d2016-10-27 14:22:27 -07001577 nextState = Math.min(nextState, Fragment.INITIALIZING);
George Mounteca8e222016-07-07 13:13:05 -07001578 }
1579 }
George Mount86bfc662016-07-12 16:06:06 -07001580
1581 moveToState(f, nextState, f.getNextTransition(), f.getNextTransitionStyle(), false);
George Mounteca8e222016-07-07 13:13:05 -07001582
1583 if (f.mView != null) {
George Mount86bfc662016-07-12 16:06:06 -07001584 // Move the view if it is out of order
George Mounteca8e222016-07-07 13:13:05 -07001585 Fragment underFragment = findFragmentUnder(f);
1586 if (underFragment != null) {
1587 final View underView = underFragment.mView;
1588 // make sure this fragment is in the right order.
1589 final ViewGroup container = f.mContainer;
1590 int underIndex = container.indexOfChild(underView);
1591 int viewIndex = container.indexOfChild(f.mView);
1592 if (viewIndex < underIndex) {
1593 container.removeViewAt(viewIndex);
1594 container.addView(f.mView, underIndex);
1595 }
1596 }
George Mount86bfc662016-07-12 16:06:06 -07001597 if (f.mIsNewlyAdded && f.mContainer != null) {
1598 // Make it visible and run the animations
George Mountc21dfd92017-01-05 16:50:25 -08001599 f.mView.setTransitionAlpha(1f);
George Mount86bfc662016-07-12 16:06:06 -07001600 f.mIsNewlyAdded = false;
1601 // run animations:
1602 Animator anim = loadAnimator(f, f.getNextTransition(), true, f.getNextTransitionStyle());
1603 if (anim != null) {
1604 anim.setTarget(f.mView);
1605 setHWLayerAnimListenerIfAlpha(f.mView, anim);
1606 anim.start();
1607 }
1608 }
George Mounteca8e222016-07-07 13:13:05 -07001609 }
1610 if (f.mHiddenChanged) {
1611 completeShowHideFragment(f);
1612 }
1613 }
1614
George Mount687e5502016-11-02 14:33:18 -07001615 /**
1616 * Changes the state of the fragment manager to {@code newState}. If the fragment manager
1617 * changes state or {@code always} is {@code true}, any fragments within it have their
1618 * states updated as well.
1619 *
1620 * @param newState The new state for the fragment manager
1621 * @param always If {@code true}, all fragments update their state, even
1622 * if {@code newState} matches the current fragment manager's state.
1623 */
1624 void moveToState(int newState, boolean always) {
Todd Kennedya5fc6f02015-04-14 18:22:54 -07001625 if (mHost == null && newState != Fragment.INITIALIZING) {
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001626 throw new IllegalStateException("No activity");
1627 }
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001628
George Mount687e5502016-11-02 14:33:18 -07001629 if (!always && mCurState == newState) {
1630 return;
1631 }
1632
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001633 mCurState = newState;
George Mounteca8e222016-07-07 13:13:05 -07001634
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001635 if (mActive != null) {
Adam Powell635c60a2011-10-26 10:22:16 -07001636 boolean loadersRunning = false;
George Mounteca8e222016-07-07 13:13:05 -07001637
1638 // Must add them in the proper order. mActive fragments may be out of order
George Mount7cdd49a2017-05-22 16:21:09 -07001639 final int numAdded = mAdded.size();
1640 for (int i = 0; i < numAdded; i++) {
1641 Fragment f = mAdded.get(i);
1642 moveFragmentToExpectedState(f);
1643 if (f.mLoaderManager != null) {
1644 loadersRunning |= f.mLoaderManager.hasRunningLoaders();
George Mounteca8e222016-07-07 13:13:05 -07001645 }
1646 }
1647
1648 // Now iterate through all active fragments. These will include those that are removed
1649 // and detached.
1650 final int numActive = mActive.size();
1651 for (int i = 0; i < numActive; i++) {
George Mount838166d2017-03-23 14:23:29 -07001652 Fragment f = mActive.valueAt(i);
George Mount86bfc662016-07-12 16:06:06 -07001653 if (f != null && (f.mRemoving || f.mDetached) && !f.mIsNewlyAdded) {
George Mounteca8e222016-07-07 13:13:05 -07001654 moveFragmentToExpectedState(f);
Adam Powell635c60a2011-10-26 10:22:16 -07001655 if (f.mLoaderManager != null) {
1656 loadersRunning |= f.mLoaderManager.hasRunningLoaders();
1657 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001658 }
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001659 }
Dianne Hackborn5f36c962010-08-26 15:54:17 -07001660
Adam Powell635c60a2011-10-26 10:22:16 -07001661 if (!loadersRunning) {
1662 startPendingDeferredFragments();
1663 }
1664
Todd Kennedya5fc6f02015-04-14 18:22:54 -07001665 if (mNeedMenuInvalidate && mHost != null && mCurState == Fragment.RESUMED) {
1666 mHost.onInvalidateOptionsMenu();
Dianne Hackborn5f36c962010-08-26 15:54:17 -07001667 mNeedMenuInvalidate = false;
1668 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001669 }
1670 }
George Mount86bfc662016-07-12 16:06:06 -07001671
Adam Powell635c60a2011-10-26 10:22:16 -07001672 void startPendingDeferredFragments() {
Adam Powell37510902011-10-31 11:48:24 -07001673 if (mActive == null) return;
1674
Adam Powell635c60a2011-10-26 10:22:16 -07001675 for (int i=0; i<mActive.size(); i++) {
George Mount838166d2017-03-23 14:23:29 -07001676 Fragment f = mActive.valueAt(i);
Adam Powell635c60a2011-10-26 10:22:16 -07001677 if (f != null) {
1678 performPendingDeferredStart(f);
1679 }
1680 }
1681 }
1682
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001683 void makeActive(Fragment f) {
1684 if (f.mIndex >= 0) {
1685 return;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001686 }
George Mount838166d2017-03-23 14:23:29 -07001687
1688 f.setIndex(mNextFragmentIndex++, mParent);
1689 if (mActive == null) {
1690 mActive = new SparseArray<>();
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001691 }
George Mount838166d2017-03-23 14:23:29 -07001692 mActive.put(f.mIndex, f);
Dianne Hackborn03fcc332012-05-15 12:49:40 -07001693 if (DEBUG) Log.v(TAG, "Allocated fragment index " + f);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001694 }
1695
1696 void makeInactive(Fragment f) {
1697 if (f.mIndex < 0) {
1698 return;
1699 }
1700
Dianne Hackborn03fcc332012-05-15 12:49:40 -07001701 if (DEBUG) Log.v(TAG, "Freeing fragment index " + f);
George Mount838166d2017-03-23 14:23:29 -07001702 // Don't remove yet. That happens in burpActive(). This prevents
1703 // concurrent modification while iterating over mActive
1704 mActive.put(f.mIndex, null);
Todd Kennedya5fc6f02015-04-14 18:22:54 -07001705 mHost.inactivateFragment(f.mWho);
Dianne Hackbornafc4b282011-06-10 17:03:42 -07001706 f.initState();
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001707 }
1708
1709 public void addFragment(Fragment fragment, boolean moveToStateNow) {
Dianne Hackborn5e0d5952010-08-05 13:45:35 -07001710 if (DEBUG) Log.v(TAG, "add: " + fragment);
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001711 makeActive(fragment);
1712 if (!fragment.mDetached) {
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07001713 if (mAdded.contains(fragment)) {
1714 throw new IllegalStateException("Fragment already added: " + fragment);
1715 }
George Mountc7146be2017-03-29 14:13:03 +00001716 synchronized (mAdded) {
1717 mAdded.add(fragment);
1718 }
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001719 fragment.mAdded = true;
1720 fragment.mRemoving = false;
George Mounteca8e222016-07-07 13:13:05 -07001721 if (fragment.mView == null) {
1722 fragment.mHiddenChanged = false;
1723 }
Dianne Hackborn6c285972011-08-29 16:53:49 -07001724 if (fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001725 mNeedMenuInvalidate = true;
1726 }
1727 if (moveToStateNow) {
1728 moveToState(fragment);
1729 }
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07001730 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001731 }
George Mounteca8e222016-07-07 13:13:05 -07001732
1733 public void removeFragment(Fragment fragment) {
Dianne Hackborn5e0d5952010-08-05 13:45:35 -07001734 if (DEBUG) Log.v(TAG, "remove: " + fragment + " nesting=" + fragment.mBackStackNesting);
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001735 final boolean inactive = !fragment.isInBackStack();
1736 if (!fragment.mDetached || inactive) {
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07001737 if (false) {
1738 // Would be nice to catch a bad remove here, but we need
1739 // time to test this to make sure we aren't crashes cases
1740 // where it is not a problem.
1741 if (!mAdded.contains(fragment)) {
1742 throw new IllegalStateException("Fragment not added: " + fragment);
1743 }
1744 }
George Mount7cdd49a2017-05-22 16:21:09 -07001745 synchronized (mAdded) {
1746 mAdded.remove(fragment);
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001747 }
Dianne Hackborn6c285972011-08-29 16:53:49 -07001748 if (fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001749 mNeedMenuInvalidate = true;
1750 }
1751 fragment.mAdded = false;
1752 fragment.mRemoving = true;
Dianne Hackborn5e0d5952010-08-05 13:45:35 -07001753 }
Dianne Hackbornf121be72010-05-06 14:10:32 -07001754 }
George Mounteca8e222016-07-07 13:13:05 -07001755
1756 /**
1757 * Marks a fragment as hidden to be later animated in with
1758 * {@link #completeShowHideFragment(Fragment)}.
1759 *
1760 * @param fragment The fragment to be shown.
1761 */
1762 public void hideFragment(Fragment fragment) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001763 if (DEBUG) Log.v(TAG, "hide: " + fragment);
1764 if (!fragment.mHidden) {
1765 fragment.mHidden = true;
George Mounteca8e222016-07-07 13:13:05 -07001766 // Toggle hidden changed so that if a fragment goes through show/hide/show
1767 // it doesn't go through the animation.
1768 fragment.mHiddenChanged = !fragment.mHiddenChanged;
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001769 }
1770 }
George Mounteca8e222016-07-07 13:13:05 -07001771
1772 /**
1773 * Marks a fragment as shown to be later animated in with
1774 * {@link #completeShowHideFragment(Fragment)}.
1775 *
1776 * @param fragment The fragment to be shown.
1777 */
1778 public void showFragment(Fragment fragment) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001779 if (DEBUG) Log.v(TAG, "show: " + fragment);
1780 if (fragment.mHidden) {
1781 fragment.mHidden = false;
George Mounteca8e222016-07-07 13:13:05 -07001782 // Toggle hidden changed so that if a fragment goes through show/hide/show
1783 // it doesn't go through the animation.
1784 fragment.mHiddenChanged = !fragment.mHiddenChanged;
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001785 }
1786 }
George Mounteca8e222016-07-07 13:13:05 -07001787
1788 public void detachFragment(Fragment fragment) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001789 if (DEBUG) Log.v(TAG, "detach: " + fragment);
1790 if (!fragment.mDetached) {
1791 fragment.mDetached = true;
1792 if (fragment.mAdded) {
1793 // We are not already in back stack, so need to remove the fragment.
George Mount7cdd49a2017-05-22 16:21:09 -07001794 if (DEBUG) Log.v(TAG, "remove from detach: " + fragment);
1795 synchronized (mAdded) {
1796 mAdded.remove(fragment);
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001797 }
Dianne Hackborn6c285972011-08-29 16:53:49 -07001798 if (fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001799 mNeedMenuInvalidate = true;
1800 }
1801 fragment.mAdded = false;
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001802 }
1803 }
1804 }
1805
George Mounteca8e222016-07-07 13:13:05 -07001806 public void attachFragment(Fragment fragment) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001807 if (DEBUG) Log.v(TAG, "attach: " + fragment);
1808 if (fragment.mDetached) {
1809 fragment.mDetached = false;
1810 if (!fragment.mAdded) {
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07001811 if (mAdded.contains(fragment)) {
1812 throw new IllegalStateException("Fragment already added: " + fragment);
1813 }
1814 if (DEBUG) Log.v(TAG, "add from attach: " + fragment);
George Mountc7146be2017-03-29 14:13:03 +00001815 synchronized (mAdded) {
1816 mAdded.add(fragment);
1817 }
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001818 fragment.mAdded = true;
Dianne Hackborn6c285972011-08-29 16:53:49 -07001819 if (fragment.mHasMenu && fragment.mMenuVisible) {
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001820 mNeedMenuInvalidate = true;
1821 }
Dianne Hackborn16f6e892011-04-15 19:00:20 -07001822 }
1823 }
1824 }
1825
Dianne Hackbornf121be72010-05-06 14:10:32 -07001826 public Fragment findFragmentById(int id) {
George Mount7cdd49a2017-05-22 16:21:09 -07001827 // First look through added fragments.
1828 for (int i = mAdded.size() - 1; i >= 0; i--) {
1829 Fragment f = mAdded.get(i);
1830 if (f != null && f.mFragmentId == id) {
1831 return f;
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001832 }
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001833 }
1834 if (mActive != null) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001835 // Now for any known fragment.
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001836 for (int i=mActive.size()-1; i>=0; i--) {
George Mount838166d2017-03-23 14:23:29 -07001837 Fragment f = mActive.valueAt(i);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001838 if (f != null && f.mFragmentId == id) {
Dianne Hackbornf121be72010-05-06 14:10:32 -07001839 return f;
1840 }
1841 }
1842 }
1843 return null;
Dianne Hackborn2dedce62010-04-15 14:45:25 -07001844 }
1845
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001846 public Fragment findFragmentByTag(String tag) {
George Mount7cdd49a2017-05-22 16:21:09 -07001847 if (tag != null) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001848 // First look through added fragments.
1849 for (int i=mAdded.size()-1; i>=0; i--) {
1850 Fragment f = mAdded.get(i);
1851 if (f != null && tag.equals(f.mTag)) {
1852 return f;
1853 }
1854 }
Dianne Hackbornacdfbcc2012-06-19 15:07:05 -07001855 }
1856 if (mActive != null && tag != null) {
Dianne Hackborn5ae74d62010-05-19 19:14:57 -07001857 // Now for any known fragment.
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001858 for (int i=mActive.size()-1; i>=0; i--) {
George Mount838166d2017-03-23 14:23:29 -07001859 Fragment f = mActive.valueAt(i);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001860 if (f != null && tag.equals(f.mTag)) {
1861 return f;
1862 }
1863 }
1864 }
1865 return null;
1866 }
George Mount7cdd49a2017-05-22 16:21:09 -07001867
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07001868 public Fragment findFragmentByWho(String who) {
1869 if (mActive != null && who != null) {
1870 for (int i=mActive.size()-1; i>=0; i--) {
George Mount838166d2017-03-23 14:23:29 -07001871 Fragment f = mActive.valueAt(i);
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07001872 if (f != null && (f=f.findFragmentByWho(who)) != null) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07001873 return f;
1874 }
1875 }
1876 }
1877 return null;
1878 }
1879
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001880 private void checkStateLoss() {
1881 if (mStateSaved) {
1882 throw new IllegalStateException(
1883 "Can not perform this action after onSaveInstanceState");
1884 }
1885 if (mNoTransactionsBecause != null) {
1886 throw new IllegalStateException(
1887 "Can not perform this action inside of " + mNoTransactionsBecause);
1888 }
1889 }
1890
George Mount27b0dc02017-02-21 10:24:09 -08001891 @Override
Adam Powelladfd62c2017-01-31 14:54:07 -08001892 public boolean isStateSaved() {
1893 return mStateSaved;
1894 }
1895
Alan Viverette95a46092013-08-14 11:17:25 -07001896 /**
1897 * Adds an action to the queue of pending actions.
1898 *
1899 * @param action the action to add
1900 * @param allowStateLoss whether to allow loss of state information
1901 * @throws IllegalStateException if the activity has been destroyed
1902 */
George Mounteca8e222016-07-07 13:13:05 -07001903 public void enqueueAction(OpGenerator action, boolean allowStateLoss) {
Dianne Hackborn6908cd12010-11-08 15:11:16 -08001904 if (!allowStateLoss) {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08001905 checkStateLoss();
Dianne Hackbornfb3cffe2010-10-25 17:08:56 -07001906 }
Dianne Hackborn445646c2010-06-25 15:52:59 -07001907 synchronized (this) {
Todd Kennedya5fc6f02015-04-14 18:22:54 -07001908 if (mDestroyed || mHost == null) {
George Mountfe0ad1c2017-03-30 12:34:42 -07001909 if (allowStateLoss) {
1910 // This FragmentManager isn't attached, so drop the entire transaction.
1911 return;
1912 }
Dianne Hackborn6908cd12010-11-08 15:11:16 -08001913 throw new IllegalStateException("Activity has been destroyed");
1914 }
Dianne Hackborn445646c2010-06-25 15:52:59 -07001915 if (mPendingActions == null) {
George Mounteca8e222016-07-07 13:13:05 -07001916 mPendingActions = new ArrayList<>();
Dianne Hackborn445646c2010-06-25 15:52:59 -07001917 }
1918 mPendingActions.add(action);
George Mount86bfc662016-07-12 16:06:06 -07001919 scheduleCommit();
1920 }
1921 }
1922
1923 /**
1924 * Schedules the execution when one hasn't been scheduled already. This should happen
1925 * the first time {@link #enqueueAction(OpGenerator, boolean)} is called or when
1926 * a postponed transaction has been started with
1927 * {@link Fragment#startPostponedEnterTransition()}
1928 */
1929 private void scheduleCommit() {
1930 synchronized (this) {
1931 boolean postponeReady =
1932 mPostponedTransactions != null && !mPostponedTransactions.isEmpty();
1933 boolean pendingReady = mPendingActions != null && mPendingActions.size() == 1;
1934 if (postponeReady || pendingReady) {
Todd Kennedya5fc6f02015-04-14 18:22:54 -07001935 mHost.getHandler().removeCallbacks(mExecCommit);
1936 mHost.getHandler().post(mExecCommit);
Dianne Hackborn445646c2010-06-25 15:52:59 -07001937 }
1938 }
1939 }
1940
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001941 public int allocBackStackIndex(BackStackRecord bse) {
Dianne Hackborndd913a52010-07-22 12:17:04 -07001942 synchronized (this) {
1943 if (mAvailBackStackIndices == null || mAvailBackStackIndices.size() <= 0) {
1944 if (mBackStackIndices == null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001945 mBackStackIndices = new ArrayList<BackStackRecord>();
Dianne Hackborndd913a52010-07-22 12:17:04 -07001946 }
1947 int index = mBackStackIndices.size();
1948 if (DEBUG) Log.v(TAG, "Setting back stack index " + index + " to " + bse);
1949 mBackStackIndices.add(bse);
1950 return index;
1951
1952 } else {
1953 int index = mAvailBackStackIndices.remove(mAvailBackStackIndices.size()-1);
1954 if (DEBUG) Log.v(TAG, "Adding back stack index " + index + " with " + bse);
1955 mBackStackIndices.set(index, bse);
1956 return index;
1957 }
1958 }
1959 }
1960
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001961 public void setBackStackIndex(int index, BackStackRecord bse) {
Dianne Hackborndd913a52010-07-22 12:17:04 -07001962 synchronized (this) {
1963 if (mBackStackIndices == null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07001964 mBackStackIndices = new ArrayList<BackStackRecord>();
Dianne Hackborndd913a52010-07-22 12:17:04 -07001965 }
1966 int N = mBackStackIndices.size();
1967 if (index < N) {
1968 if (DEBUG) Log.v(TAG, "Setting back stack index " + index + " to " + bse);
1969 mBackStackIndices.set(index, bse);
1970 } else {
1971 while (N < index) {
1972 mBackStackIndices.add(null);
1973 if (mAvailBackStackIndices == null) {
1974 mAvailBackStackIndices = new ArrayList<Integer>();
1975 }
1976 if (DEBUG) Log.v(TAG, "Adding available back stack index " + N);
1977 mAvailBackStackIndices.add(N);
1978 N++;
1979 }
1980 if (DEBUG) Log.v(TAG, "Adding back stack index " + index + " with " + bse);
1981 mBackStackIndices.add(bse);
1982 }
1983 }
1984 }
1985
1986 public void freeBackStackIndex(int index) {
1987 synchronized (this) {
1988 mBackStackIndices.set(index, null);
1989 if (mAvailBackStackIndices == null) {
1990 mAvailBackStackIndices = new ArrayList<Integer>();
1991 }
1992 if (DEBUG) Log.v(TAG, "Freeing back stack index " + index);
1993 mAvailBackStackIndices.add(index);
1994 }
1995 }
1996
George Mounteca8e222016-07-07 13:13:05 -07001997 /**
1998 * Broken out from exec*, this prepares for gathering and executing operations.
1999 *
2000 * @param allowStateLoss true if state loss should be ignored or false if it should be
2001 * checked.
2002 */
2003 private void ensureExecReady(boolean allowStateLoss) {
Adam Powell8585ed62016-02-04 15:38:20 -08002004 if (mExecutingActions) {
2005 throw new IllegalStateException("FragmentManager is already executing transactions");
2006 }
2007
2008 if (Looper.myLooper() != mHost.getHandler().getLooper()) {
2009 throw new IllegalStateException("Must be called from main thread of fragment host");
2010 }
2011
Adam Powell3518fed2016-03-01 09:07:44 -08002012 if (!allowStateLoss) {
Adam Powell8585ed62016-02-04 15:38:20 -08002013 checkStateLoss();
2014 }
2015
George Mounteca8e222016-07-07 13:13:05 -07002016 if (mTmpRecords == null) {
2017 mTmpRecords = new ArrayList<>();
2018 mTmpIsPop = new ArrayList<>();
2019 }
George Mount521862d2017-02-17 08:01:03 -08002020 mExecutingActions = true;
2021 try {
2022 executePostponedTransaction(null, null);
2023 } finally {
2024 mExecutingActions = false;
2025 }
George Mounteca8e222016-07-07 13:13:05 -07002026 }
2027
2028 public void execSingleAction(OpGenerator action, boolean allowStateLoss) {
George Mountfe0ad1c2017-03-30 12:34:42 -07002029 if (allowStateLoss && (mHost == null || mDestroyed)) {
2030 // This FragmentManager isn't attached, so drop the entire transaction.
2031 return;
2032 }
George Mounteca8e222016-07-07 13:13:05 -07002033 ensureExecReady(allowStateLoss);
2034 if (action.generateOps(mTmpRecords, mTmpIsPop)) {
2035 mExecutingActions = true;
2036 try {
George Mounta0ffaff2017-04-26 13:10:59 -07002037 removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
George Mounteca8e222016-07-07 13:13:05 -07002038 } finally {
2039 cleanupExec();
2040 }
George Mountc8c2bdf2016-06-30 17:08:27 -07002041 }
Adam Powell8585ed62016-02-04 15:38:20 -08002042
2043 doPendingDeferredStart();
George Mount838166d2017-03-23 14:23:29 -07002044 burpActive();
Adam Powell8585ed62016-02-04 15:38:20 -08002045 }
2046
Dianne Hackborn445646c2010-06-25 15:52:59 -07002047 /**
George Mounteca8e222016-07-07 13:13:05 -07002048 * Broken out of exec*, this cleans up the mExecutingActions and the temporary structures
2049 * used in executing operations.
2050 */
2051 private void cleanupExec() {
2052 mExecutingActions = false;
2053 mTmpIsPop.clear();
2054 mTmpRecords.clear();
2055 }
2056
2057 /**
Dianne Hackborn445646c2010-06-25 15:52:59 -07002058 * Only call from main thread!
2059 */
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08002060 public boolean execPendingActions() {
George Mounteca8e222016-07-07 13:13:05 -07002061 ensureExecReady(true);
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08002062
2063 boolean didSomething = false;
George Mounteca8e222016-07-07 13:13:05 -07002064 while (generateOpsForPendingActions(mTmpRecords, mTmpIsPop)) {
Dianne Hackborn445646c2010-06-25 15:52:59 -07002065 mExecutingActions = true;
George Mountc8c2bdf2016-06-30 17:08:27 -07002066 try {
George Mounta0ffaff2017-04-26 13:10:59 -07002067 removeRedundantOperationsAndExecute(mTmpRecords, mTmpIsPop);
George Mountc8c2bdf2016-06-30 17:08:27 -07002068 } finally {
George Mounteca8e222016-07-07 13:13:05 -07002069 cleanupExec();
Dianne Hackborn445646c2010-06-25 15:52:59 -07002070 }
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08002071 didSomething = true;
Dianne Hackborn445646c2010-06-25 15:52:59 -07002072 }
Adam Powell78fed9b2011-11-07 10:45:34 -08002073
Adam Powell8585ed62016-02-04 15:38:20 -08002074 doPendingDeferredStart();
George Mount838166d2017-03-23 14:23:29 -07002075 burpActive();
Adam Powell8585ed62016-02-04 15:38:20 -08002076
2077 return didSomething;
2078 }
2079
George Mounteca8e222016-07-07 13:13:05 -07002080 /**
George Mount86bfc662016-07-12 16:06:06 -07002081 * Complete the execution of transactions that have previously been postponed, but are
2082 * now ready.
2083 */
2084 private void executePostponedTransaction(ArrayList<BackStackRecord> records,
2085 ArrayList<Boolean> isRecordPop) {
2086 int numPostponed = mPostponedTransactions == null ? 0 : mPostponedTransactions.size();
2087 for (int i = 0; i < numPostponed; i++) {
2088 StartEnterTransitionListener listener = mPostponedTransactions.get(i);
2089 if (records != null && !listener.mIsBack) {
2090 int index = records.indexOf(listener.mRecord);
2091 if (index != -1 && isRecordPop.get(index)) {
2092 listener.cancelTransaction();
2093 continue;
2094 }
2095 }
2096 if (listener.isReady() || (records != null &&
2097 listener.mRecord.interactsWith(records, 0, records.size()))) {
2098 mPostponedTransactions.remove(i);
2099 i--;
2100 numPostponed--;
2101 int index;
2102 if (records != null && !listener.mIsBack &&
2103 (index = records.indexOf(listener.mRecord)) != -1 &&
2104 isRecordPop.get(index)) {
2105 // This is popping a postponed transaction
2106 listener.cancelTransaction();
2107 } else {
2108 listener.completeTransaction();
2109 }
2110 }
2111 }
2112 }
2113
2114 /**
George Mounta0ffaff2017-04-26 13:10:59 -07002115 * Remove redundant BackStackRecord operations and executes them. This method merges operations
2116 * of proximate records that allow reordering. See
2117 * {@link FragmentTransaction#setReorderingAllowed(boolean)}.
George Mounteca8e222016-07-07 13:13:05 -07002118 * <p>
2119 * For example, a transaction that adds to the back stack and then another that pops that
George Mounta0ffaff2017-04-26 13:10:59 -07002120 * back stack record will be optimized to remove the unnecessary operation.
George Mounteca8e222016-07-07 13:13:05 -07002121 * <p>
2122 * Likewise, two transactions committed that are executed at the same time will be optimized
George Mounta0ffaff2017-04-26 13:10:59 -07002123 * to remove the redundant operations as well as two pop operations executed together.
George Mounteca8e222016-07-07 13:13:05 -07002124 *
2125 * @param records The records pending execution
2126 * @param isRecordPop The direction that these records are being run.
2127 */
George Mounta0ffaff2017-04-26 13:10:59 -07002128 private void removeRedundantOperationsAndExecute(ArrayList<BackStackRecord> records,
George Mounteca8e222016-07-07 13:13:05 -07002129 ArrayList<Boolean> isRecordPop) {
2130 if (records == null || records.isEmpty()) {
2131 return;
2132 }
2133
2134 if (isRecordPop == null || records.size() != isRecordPop.size()) {
2135 throw new IllegalStateException("Internal error with the back stack records");
2136 }
2137
George Mount86bfc662016-07-12 16:06:06 -07002138 // Force start of any postponed transactions that interact with scheduled transactions:
2139 executePostponedTransaction(records, isRecordPop);
2140
George Mounteca8e222016-07-07 13:13:05 -07002141 final int numRecords = records.size();
2142 int startIndex = 0;
2143 for (int recordNum = 0; recordNum < numRecords; recordNum++) {
George Mounta0ffaff2017-04-26 13:10:59 -07002144 final boolean canReorder = records.get(recordNum).mReorderingAllowed;
2145 if (!canReorder) {
George Mounteca8e222016-07-07 13:13:05 -07002146 // execute all previous transactions
2147 if (startIndex != recordNum) {
2148 executeOpsTogether(records, isRecordPop, startIndex, recordNum);
2149 }
George Mounta0ffaff2017-04-26 13:10:59 -07002150 // execute all pop operations that don't allow reordering together or
2151 // one add operation
2152 int reorderingEnd = recordNum + 1;
George Mounta27a23702017-01-17 15:35:46 -08002153 if (isRecordPop.get(recordNum)) {
George Mounta0ffaff2017-04-26 13:10:59 -07002154 while (reorderingEnd < numRecords
2155 && isRecordPop.get(reorderingEnd)
2156 && !records.get(reorderingEnd).mReorderingAllowed) {
2157 reorderingEnd++;
George Mounteca8e222016-07-07 13:13:05 -07002158 }
2159 }
George Mounta0ffaff2017-04-26 13:10:59 -07002160 executeOpsTogether(records, isRecordPop, recordNum, reorderingEnd);
2161 startIndex = reorderingEnd;
2162 recordNum = reorderingEnd - 1;
George Mounteca8e222016-07-07 13:13:05 -07002163 }
2164 }
2165 if (startIndex != numRecords) {
2166 executeOpsTogether(records, isRecordPop, startIndex, numRecords);
2167 }
2168 }
2169
2170 /**
George Mounta0ffaff2017-04-26 13:10:59 -07002171 * Executes a subset of a list of BackStackRecords, all of which either allow reordering or
2172 * do not allow ordering.
2173 * @param records A list of BackStackRecords that are to be executed together
George Mounteca8e222016-07-07 13:13:05 -07002174 * @param isRecordPop The direction that these records are being run.
George Mounta0ffaff2017-04-26 13:10:59 -07002175 * @param startIndex The index of the first record in <code>records</code> to be executed
2176 * @param endIndex One more than the final record index in <code>records</code> to executed.
George Mounteca8e222016-07-07 13:13:05 -07002177 */
2178 private void executeOpsTogether(ArrayList<BackStackRecord> records,
2179 ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
George Mounta0ffaff2017-04-26 13:10:59 -07002180 final boolean allowReordering = records.get(startIndex).mReorderingAllowed;
George Mounteca8e222016-07-07 13:13:05 -07002181 boolean addToBackStack = false;
2182 if (mTmpAddedFragments == null) {
2183 mTmpAddedFragments = new ArrayList<>();
George Mounteca8e222016-07-07 13:13:05 -07002184 } else {
2185 mTmpAddedFragments.clear();
George Mounteca8e222016-07-07 13:13:05 -07002186 }
George Mount7cdd49a2017-05-22 16:21:09 -07002187 mTmpAddedFragments.addAll(mAdded);
Adam Powell5f3a05c2017-01-27 16:51:03 -08002188 Fragment oldPrimaryNav = getPrimaryNavigationFragment();
George Mounteca8e222016-07-07 13:13:05 -07002189 for (int recordNum = startIndex; recordNum < endIndex; recordNum++) {
2190 final BackStackRecord record = records.get(recordNum);
2191 final boolean isPop = isRecordPop.get(recordNum);
2192 if (!isPop) {
Adam Powell5f3a05c2017-01-27 16:51:03 -08002193 oldPrimaryNav = record.expandOps(mTmpAddedFragments, oldPrimaryNav);
George Mount99c532d2017-01-11 10:23:40 -08002194 } else {
2195 record.trackAddedFragmentsInPop(mTmpAddedFragments);
George Mounteca8e222016-07-07 13:13:05 -07002196 }
George Mounteca8e222016-07-07 13:13:05 -07002197 addToBackStack = addToBackStack || record.mAddToBackStack;
George Mounteca8e222016-07-07 13:13:05 -07002198 }
2199 mTmpAddedFragments.clear();
2200
George Mounta0ffaff2017-04-26 13:10:59 -07002201 if (!allowReordering) {
George Mount86bfc662016-07-12 16:06:06 -07002202 FragmentTransition.startTransitions(this, records, isRecordPop, startIndex, endIndex,
2203 false);
George Mounteca8e222016-07-07 13:13:05 -07002204 }
2205 executeOps(records, isRecordPop, startIndex, endIndex);
2206
George Mount86bfc662016-07-12 16:06:06 -07002207 int postponeIndex = endIndex;
George Mounta0ffaff2017-04-26 13:10:59 -07002208 if (allowReordering) {
George Mountc21dfd92017-01-05 16:50:25 -08002209 ArraySet<Fragment> addedFragments = new ArraySet<>();
2210 addAddedFragments(addedFragments);
George Mount86bfc662016-07-12 16:06:06 -07002211 postponeIndex = postponePostponableTransactions(records, isRecordPop,
George Mountc21dfd92017-01-05 16:50:25 -08002212 startIndex, endIndex, addedFragments);
2213 makeRemovedFragmentsInvisible(addedFragments);
George Mount86bfc662016-07-12 16:06:06 -07002214 }
2215
George Mounta0ffaff2017-04-26 13:10:59 -07002216 if (postponeIndex != startIndex && allowReordering) {
George Mount86bfc662016-07-12 16:06:06 -07002217 // need to run something now
2218 FragmentTransition.startTransitions(this, records, isRecordPop, startIndex,
2219 postponeIndex, true);
George Mount687e5502016-11-02 14:33:18 -07002220 moveToState(mCurState, true);
George Mounteca8e222016-07-07 13:13:05 -07002221 }
2222
2223 for (int recordNum = startIndex; recordNum < endIndex; recordNum++) {
2224 final BackStackRecord record = records.get(recordNum);
2225 final boolean isPop = isRecordPop.get(recordNum);
2226 if (isPop && record.mIndex >= 0) {
2227 freeBackStackIndex(record.mIndex);
2228 record.mIndex = -1;
2229 }
Adam Powelladfd62c2017-01-31 14:54:07 -08002230 record.runOnCommitRunnables();
George Mounteca8e222016-07-07 13:13:05 -07002231 }
George Mount86bfc662016-07-12 16:06:06 -07002232
George Mounteca8e222016-07-07 13:13:05 -07002233 if (addToBackStack) {
2234 reportBackStackChanged();
2235 }
2236 }
2237
2238 /**
George Mountc21dfd92017-01-05 16:50:25 -08002239 * Any fragments that were removed because they have been postponed should have their views
2240 * made invisible by setting their transition alpha to 0.
2241 *
2242 * @param fragments The fragments that were added during operation execution. Only the ones
2243 * that are no longer added will have their transition alpha changed.
2244 */
2245 private void makeRemovedFragmentsInvisible(ArraySet<Fragment> fragments) {
2246 final int numAdded = fragments.size();
2247 for (int i = 0; i < numAdded; i++) {
2248 final Fragment fragment = fragments.valueAt(i);
2249 if (!fragment.mAdded) {
2250 final View view = fragment.getView();
2251 view.setTransitionAlpha(0f);
2252 }
2253 }
2254 }
2255
2256 /**
George Mount86bfc662016-07-12 16:06:06 -07002257 * Examine all transactions and determine which ones are marked as postponed. Those will
2258 * have their operations rolled back and moved to the end of the record list (up to endIndex).
2259 * It will also add the postponed transaction to the queue.
2260 *
2261 * @param records A list of BackStackRecords that should be checked.
2262 * @param isRecordPop The direction that these records are being run.
2263 * @param startIndex The index of the first record in <code>records</code> to be checked
2264 * @param endIndex One more than the final record index in <code>records</code> to be checked.
2265 * @return The index of the first postponed transaction or endIndex if no transaction was
2266 * postponed.
2267 */
2268 private int postponePostponableTransactions(ArrayList<BackStackRecord> records,
George Mountc21dfd92017-01-05 16:50:25 -08002269 ArrayList<Boolean> isRecordPop, int startIndex, int endIndex,
2270 ArraySet<Fragment> added) {
George Mount86bfc662016-07-12 16:06:06 -07002271 int postponeIndex = endIndex;
2272 for (int i = endIndex - 1; i >= startIndex; i--) {
2273 final BackStackRecord record = records.get(i);
2274 final boolean isPop = isRecordPop.get(i);
2275 boolean isPostponed = record.isPostponed() &&
2276 !record.interactsWith(records, i + 1, endIndex);
2277 if (isPostponed) {
2278 if (mPostponedTransactions == null) {
2279 mPostponedTransactions = new ArrayList<>();
2280 }
2281 StartEnterTransitionListener listener =
2282 new StartEnterTransitionListener(record, isPop);
2283 mPostponedTransactions.add(listener);
2284 record.setOnStartPostponedListener(listener);
2285
2286 // roll back the transaction
2287 if (isPop) {
2288 record.executeOps();
2289 } else {
George Mounta42f8e42017-02-08 10:52:02 -08002290 record.executePopOps(false);
George Mount86bfc662016-07-12 16:06:06 -07002291 }
2292
2293 // move to the end
2294 postponeIndex--;
2295 if (i != postponeIndex) {
2296 records.remove(i);
2297 records.add(postponeIndex, record);
2298 }
2299
2300 // different views may be visible now
George Mountc21dfd92017-01-05 16:50:25 -08002301 addAddedFragments(added);
George Mount86bfc662016-07-12 16:06:06 -07002302 }
2303 }
2304 return postponeIndex;
2305 }
2306
2307 /**
2308 * When a postponed transaction is ready to be started, this completes the transaction,
2309 * removing, hiding, or showing views as well as starting the animations and transitions.
2310 * <p>
2311 * {@code runtransitions} is set to false when the transaction postponement was interrupted
2312 * abnormally -- normally by a new transaction being started that affects the postponed
2313 * transaction.
2314 *
2315 * @param record The transaction to run
2316 * @param isPop true if record is popping or false if it is adding
2317 * @param runTransitions true if the fragment transition should be run or false otherwise.
2318 * @param moveToState true if the state should be changed after executing the operations.
2319 * This is false when the transaction is canceled when a postponed
2320 * transaction is popped.
2321 */
2322 private void completeExecute(BackStackRecord record, boolean isPop, boolean runTransitions,
2323 boolean moveToState) {
George Mountc972092e2017-05-15 13:45:22 -07002324 if (isPop) {
2325 record.executePopOps(moveToState);
2326 } else {
2327 record.executeOps();
2328 }
George Mount86bfc662016-07-12 16:06:06 -07002329 ArrayList<BackStackRecord> records = new ArrayList<>(1);
2330 ArrayList<Boolean> isRecordPop = new ArrayList<>(1);
2331 records.add(record);
2332 isRecordPop.add(isPop);
George Mount86bfc662016-07-12 16:06:06 -07002333 if (runTransitions) {
2334 FragmentTransition.startTransitions(this, records, isRecordPop, 0, 1, true);
2335 }
2336 if (moveToState) {
George Mount687e5502016-11-02 14:33:18 -07002337 moveToState(mCurState, true);
George Mountc21dfd92017-01-05 16:50:25 -08002338 }
2339
2340 if (mActive != null) {
George Mount86bfc662016-07-12 16:06:06 -07002341 final int numActive = mActive.size();
2342 for (int i = 0; i < numActive; i++) {
2343 // Allow added fragments to be removed during the pop since we aren't going
2344 // to move them to the final state with moveToState(mCurState).
George Mount838166d2017-03-23 14:23:29 -07002345 Fragment fragment = mActive.valueAt(i);
George Mountc21dfd92017-01-05 16:50:25 -08002346 if (fragment != null && fragment.mView != null && fragment.mIsNewlyAdded
2347 && record.interactsWith(fragment.mContainerId)) {
George Mount86bfc662016-07-12 16:06:06 -07002348 fragment.mIsNewlyAdded = false;
2349 }
2350 }
2351 }
2352 }
2353
2354 /**
George Mounteca8e222016-07-07 13:13:05 -07002355 * Find a fragment within the fragment's container whose View should be below the passed
2356 * fragment. {@code null} is returned when the fragment has no View or if there should be
2357 * no fragment with a View below the given fragment.
2358 *
2359 * As an example, if mAdded has two Fragments with Views sharing the same container:
2360 * FragmentA
2361 * FragmentB
2362 *
2363 * Then, when processing FragmentB, FragmentA will be returned. If, however, FragmentA
2364 * had no View, null would be returned.
2365 *
2366 * @param f The fragment that may be on top of another fragment.
2367 * @return The fragment with a View under f, if one exists or null if f has no View or
2368 * there are no fragments with Views in the same container.
2369 */
2370 private Fragment findFragmentUnder(Fragment f) {
2371 final ViewGroup container = f.mContainer;
2372 final View view = f.mView;
2373
2374 if (container == null || view == null) {
2375 return null;
2376 }
2377
2378 final int fragmentIndex = mAdded.indexOf(f);
2379 for (int i = fragmentIndex - 1; i >= 0; i--) {
2380 Fragment underFragment = mAdded.get(i);
2381 if (underFragment.mContainer == container && underFragment.mView != null) {
2382 // Found the fragment under this one
2383 return underFragment;
2384 }
2385 }
2386 return null;
2387 }
2388
2389 /**
2390 * Run the operations in the BackStackRecords, either to push or pop.
2391 *
2392 * @param records The list of records whose operations should be run.
2393 * @param isRecordPop The direction that these records are being run.
2394 * @param startIndex The index of the first entry in records to run.
2395 * @param endIndex One past the index of the final entry in records to run.
2396 */
2397 private static void executeOps(ArrayList<BackStackRecord> records,
2398 ArrayList<Boolean> isRecordPop, int startIndex, int endIndex) {
2399 for (int i = startIndex; i < endIndex; i++) {
2400 final BackStackRecord record = records.get(i);
2401 final boolean isPop = isRecordPop.get(i);
2402 if (isPop) {
George Mount8c4fa362017-02-02 07:22:50 -08002403 record.bumpBackStackNesting(-1);
George Mounta42f8e42017-02-08 10:52:02 -08002404 // Only execute the add operations at the end of
2405 // all transactions.
2406 boolean moveToState = i == (endIndex - 1);
2407 record.executePopOps(moveToState);
George Mounteca8e222016-07-07 13:13:05 -07002408 } else {
George Mount8c4fa362017-02-02 07:22:50 -08002409 record.bumpBackStackNesting(1);
George Mounteca8e222016-07-07 13:13:05 -07002410 record.executeOps();
2411 }
2412 }
2413 }
2414
2415 /**
George Mount86bfc662016-07-12 16:06:06 -07002416 * Ensure that fragments that are added are moved to at least the CREATED state.
George Mountc21dfd92017-01-05 16:50:25 -08002417 * Any newly-added Views are inserted into {@code added} so that the Transaction can be
2418 * postponed with {@link Fragment#postponeEnterTransition()}. They will later be made
2419 * invisible by changing their transitionAlpha to 0 if they have been removed when postponed.
George Mounteca8e222016-07-07 13:13:05 -07002420 */
George Mountc21dfd92017-01-05 16:50:25 -08002421 private void addAddedFragments(ArraySet<Fragment> added) {
George Mount86bfc662016-07-12 16:06:06 -07002422 if (mCurState < Fragment.CREATED) {
2423 return;
2424 }
2425 // We want to leave the fragment in the started state
2426 final int state = Math.min(mCurState, Fragment.STARTED);
George Mount7cdd49a2017-05-22 16:21:09 -07002427 final int numAdded = mAdded.size();
George Mount86bfc662016-07-12 16:06:06 -07002428 for (int i = 0; i < numAdded; i++) {
2429 Fragment fragment = mAdded.get(i);
2430 if (fragment.mState < state) {
2431 moveToState(fragment, state, fragment.getNextAnim(), fragment.getNextTransition(), false);
2432 if (fragment.mView != null && !fragment.mHidden && fragment.mIsNewlyAdded) {
George Mountc21dfd92017-01-05 16:50:25 -08002433 added.add(fragment);
George Mounteca8e222016-07-07 13:13:05 -07002434 }
George Mounteca8e222016-07-07 13:13:05 -07002435 }
2436 }
2437 }
2438
2439 /**
George Mount86bfc662016-07-12 16:06:06 -07002440 * Starts all postponed transactions regardless of whether they are ready or not.
George Mounteca8e222016-07-07 13:13:05 -07002441 */
George Mount86bfc662016-07-12 16:06:06 -07002442 private void forcePostponedTransactions() {
2443 if (mPostponedTransactions != null) {
2444 while (!mPostponedTransactions.isEmpty()) {
2445 mPostponedTransactions.remove(0).completeTransaction();
2446 }
George Mounteca8e222016-07-07 13:13:05 -07002447 }
George Mount86bfc662016-07-12 16:06:06 -07002448 }
2449
2450 /**
2451 * Ends the animations of fragments so that they immediately reach the end state.
2452 * This is used prior to saving the state so that the correct state is saved.
2453 */
2454 private void endAnimatingAwayFragments() {
2455 final int numFragments = mActive == null ? 0 : mActive.size();
2456 for (int i = 0; i < numFragments; i++) {
George Mount838166d2017-03-23 14:23:29 -07002457 Fragment fragment = mActive.valueAt(i);
George Mount86bfc662016-07-12 16:06:06 -07002458 if (fragment != null && fragment.getAnimatingAway() != null) {
2459 // Give up waiting for the animation and just end it.
2460 fragment.getAnimatingAway().end();
George Mounteca8e222016-07-07 13:13:05 -07002461 }
2462 }
2463 }
2464
2465 /**
2466 * Adds all records in the pending actions to records and whether they are add or pop
2467 * operations to isPop. After executing, the pending actions will be empty.
2468 *
2469 * @param records All pending actions will generate BackStackRecords added to this.
2470 * This contains the transactions, in order, to execute.
2471 * @param isPop All pending actions will generate booleans to add to this. This contains
2472 * an entry for each entry in records to indicate whether or not it is a
2473 * pop action.
2474 */
2475 private boolean generateOpsForPendingActions(ArrayList<BackStackRecord> records,
2476 ArrayList<Boolean> isPop) {
Adam Powell5f3a05c2017-01-27 16:51:03 -08002477 boolean didSomething = false;
George Mounteca8e222016-07-07 13:13:05 -07002478 synchronized (this) {
2479 if (mPendingActions == null || mPendingActions.size() == 0) {
2480 return false;
2481 }
2482
Adam Powell5f3a05c2017-01-27 16:51:03 -08002483 final int numActions = mPendingActions.size();
George Mounteca8e222016-07-07 13:13:05 -07002484 for (int i = 0; i < numActions; i++) {
Adam Powell5f3a05c2017-01-27 16:51:03 -08002485 didSomething |= mPendingActions.get(i).generateOps(records, isPop);
George Mounteca8e222016-07-07 13:13:05 -07002486 }
2487 mPendingActions.clear();
2488 mHost.getHandler().removeCallbacks(mExecCommit);
2489 }
Adam Powell5f3a05c2017-01-27 16:51:03 -08002490 return didSomething;
George Mounteca8e222016-07-07 13:13:05 -07002491 }
2492
Adam Powell8585ed62016-02-04 15:38:20 -08002493 void doPendingDeferredStart() {
Adam Powell78fed9b2011-11-07 10:45:34 -08002494 if (mHavePendingDeferredStart) {
2495 boolean loadersRunning = false;
2496 for (int i=0; i<mActive.size(); i++) {
George Mount838166d2017-03-23 14:23:29 -07002497 Fragment f = mActive.valueAt(i);
Adam Powell78fed9b2011-11-07 10:45:34 -08002498 if (f != null && f.mLoaderManager != null) {
2499 loadersRunning |= f.mLoaderManager.hasRunningLoaders();
2500 }
2501 }
2502 if (!loadersRunning) {
2503 mHavePendingDeferredStart = false;
2504 startPendingDeferredFragments();
2505 }
2506 }
Dianne Hackborn445646c2010-06-25 15:52:59 -07002507 }
Adam Powell78fed9b2011-11-07 10:45:34 -08002508
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07002509 void reportBackStackChanged() {
2510 if (mBackStackChangeListeners != null) {
2511 for (int i=0; i<mBackStackChangeListeners.size(); i++) {
2512 mBackStackChangeListeners.get(i).onBackStackChanged();
2513 }
2514 }
2515 }
2516
2517 void addBackStackState(BackStackRecord state) {
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07002518 if (mBackStack == null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07002519 mBackStack = new ArrayList<BackStackRecord>();
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07002520 }
2521 mBackStack.add(state);
2522 }
George Mounteca8e222016-07-07 13:13:05 -07002523
2524 boolean popBackStackState(ArrayList<BackStackRecord> records, ArrayList<Boolean> isRecordPop,
2525 String name, int id, int flags) {
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07002526 if (mBackStack == null) {
2527 return false;
2528 }
George Mounteca8e222016-07-07 13:13:05 -07002529 if (name == null && id < 0 && (flags & POP_BACK_STACK_INCLUSIVE) == 0) {
2530 int last = mBackStack.size() - 1;
Dianne Hackbornf121be72010-05-06 14:10:32 -07002531 if (last < 0) {
2532 return false;
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07002533 }
George Mounteca8e222016-07-07 13:13:05 -07002534 records.add(mBackStack.remove(last));
2535 isRecordPop.add(true);
Dianne Hackbornf121be72010-05-06 14:10:32 -07002536 } else {
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07002537 int index = -1;
2538 if (name != null || id >= 0) {
2539 // If a name or ID is specified, look for that place in
2540 // the stack.
2541 index = mBackStack.size()-1;
2542 while (index >= 0) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07002543 BackStackRecord bss = mBackStack.get(index);
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07002544 if (name != null && name.equals(bss.getName())) {
2545 break;
2546 }
2547 if (id >= 0 && id == bss.mIndex) {
2548 break;
2549 }
2550 index--;
Dianne Hackbornf121be72010-05-06 14:10:32 -07002551 }
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07002552 if (index < 0) {
2553 return false;
Dianne Hackborndd913a52010-07-22 12:17:04 -07002554 }
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08002555 if ((flags&POP_BACK_STACK_INCLUSIVE) != 0) {
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07002556 index--;
2557 // Consume all following entries that match.
2558 while (index >= 0) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07002559 BackStackRecord bss = mBackStack.get(index);
Dianne Hackbornb3cf10f2010-08-03 13:07:11 -07002560 if ((name != null && name.equals(bss.getName()))
2561 || (id >= 0 && id == bss.mIndex)) {
2562 index--;
2563 continue;
2564 }
2565 break;
2566 }
2567 }
Dianne Hackborndd913a52010-07-22 12:17:04 -07002568 }
2569 if (index == mBackStack.size()-1) {
Dianne Hackbornf121be72010-05-06 14:10:32 -07002570 return false;
2571 }
George Mounteca8e222016-07-07 13:13:05 -07002572 for (int i = mBackStack.size() - 1; i > index; i--) {
2573 records.add(mBackStack.remove(i));
2574 isRecordPop.add(true);
Dianne Hackbornf121be72010-05-06 14:10:32 -07002575 }
Dianne Hackbornf121be72010-05-06 14:10:32 -07002576 }
Dianne Hackbornba51c3d2010-05-05 18:49:48 -07002577 return true;
2578 }
Adam Powell44ba79e2016-02-04 16:20:37 -08002579
2580 FragmentManagerNonConfig retainNonConfig() {
George Mountf804d6a2017-04-05 12:30:17 -07002581 setRetaining(mSavedNonConfig);
2582 return mSavedNonConfig;
2583 }
2584
2585 /**
2586 * Recurse the FragmentManagerNonConfig fragments and set the mRetaining to true. This
2587 * was previously done while saving the non-config state, but that has been moved to
2588 * {@link #saveNonConfig()} called from {@link #saveAllState()}. If mRetaining is set too
2589 * early, the fragment won't be destroyed when the FragmentManager is destroyed.
2590 */
2591 private static void setRetaining(FragmentManagerNonConfig nonConfig) {
2592 if (nonConfig == null) {
2593 return;
2594 }
2595 List<Fragment> fragments = nonConfig.getFragments();
2596 if (fragments != null) {
2597 for (Fragment fragment : fragments) {
2598 fragment.mRetaining = true;
2599 }
2600 }
2601 List<FragmentManagerNonConfig> children = nonConfig.getChildNonConfigs();
2602 if (children != null) {
2603 for (FragmentManagerNonConfig child : children) {
2604 setRetaining(child);
2605 }
2606 }
2607 }
2608
2609 void saveNonConfig() {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002610 ArrayList<Fragment> fragments = null;
Adam Powell44ba79e2016-02-04 16:20:37 -08002611 ArrayList<FragmentManagerNonConfig> childFragments = null;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07002612 if (mActive != null) {
2613 for (int i=0; i<mActive.size(); i++) {
George Mount838166d2017-03-23 14:23:29 -07002614 Fragment f = mActive.valueAt(i);
Adam Powell44ba79e2016-02-04 16:20:37 -08002615 if (f != null) {
2616 if (f.mRetainInstance) {
2617 if (fragments == null) {
2618 fragments = new ArrayList<>();
2619 }
2620 fragments.add(f);
Adam Powell44ba79e2016-02-04 16:20:37 -08002621 f.mTargetIndex = f.mTarget != null ? f.mTarget.mIndex : -1;
2622 if (DEBUG) Log.v(TAG, "retainNonConfig: keeping retained " + f);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002623 }
sergeyvbe6f5042017-05-23 15:24:37 -07002624 FragmentManagerNonConfig child;
Adam Powell44ba79e2016-02-04 16:20:37 -08002625 if (f.mChildFragmentManager != null) {
George Mountf804d6a2017-04-05 12:30:17 -07002626 f.mChildFragmentManager.saveNonConfig();
sergeyvbe6f5042017-05-23 15:24:37 -07002627 child = f.mChildFragmentManager.mSavedNonConfig;
2628 } else {
2629 // f.mChildNonConfig may be not null, when the parent fragment is
2630 // in the backstack.
2631 child = f.mChildNonConfig;
2632 }
2633
2634 if (childFragments == null && child != null) {
2635 childFragments = new ArrayList<>(mActive.size());
2636 for (int j = 0; j < i; j++) {
2637 childFragments.add(null);
Adam Powell44ba79e2016-02-04 16:20:37 -08002638 }
2639 }
sergeyvbe6f5042017-05-23 15:24:37 -07002640
2641 if (childFragments != null) {
2642 childFragments.add(child);
Adam Powell44ba79e2016-02-04 16:20:37 -08002643 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002644 }
2645 }
2646 }
Adam Powell44ba79e2016-02-04 16:20:37 -08002647 if (fragments == null && childFragments == null) {
George Mountf804d6a2017-04-05 12:30:17 -07002648 mSavedNonConfig = null;
2649 } else {
2650 mSavedNonConfig = new FragmentManagerNonConfig(fragments, childFragments);
Adam Powell44ba79e2016-02-04 16:20:37 -08002651 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002652 }
2653
2654 void saveFragmentViewState(Fragment f) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07002655 if (f.mView == null) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002656 return;
2657 }
2658 if (mStateArray == null) {
2659 mStateArray = new SparseArray<Parcelable>();
Dianne Hackbornb46ed762011-06-02 18:33:15 -07002660 } else {
2661 mStateArray.clear();
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002662 }
2663 f.mView.saveHierarchyState(mStateArray);
2664 if (mStateArray.size() > 0) {
2665 f.mSavedViewState = mStateArray;
2666 mStateArray = null;
2667 }
2668 }
2669
Dianne Hackbornb46ed762011-06-02 18:33:15 -07002670 Bundle saveFragmentBasicState(Fragment f) {
2671 Bundle result = null;
2672
2673 if (mStateBundle == null) {
2674 mStateBundle = new Bundle();
2675 }
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07002676 f.performSaveInstanceState(mStateBundle);
Adam Powell38c67ff2016-10-28 10:24:40 -07002677 dispatchOnFragmentSaveInstanceState(f, mStateBundle, false);
Dianne Hackbornb46ed762011-06-02 18:33:15 -07002678 if (!mStateBundle.isEmpty()) {
2679 result = mStateBundle;
2680 mStateBundle = null;
2681 }
2682
2683 if (f.mView != null) {
2684 saveFragmentViewState(f);
Dianne Hackborn13332762011-06-03 17:34:45 -07002685 }
2686 if (f.mSavedViewState != null) {
2687 if (result == null) {
2688 result = new Bundle();
Dianne Hackbornb46ed762011-06-02 18:33:15 -07002689 }
Dianne Hackborn13332762011-06-03 17:34:45 -07002690 result.putSparseParcelableArray(
2691 FragmentManagerImpl.VIEW_STATE_TAG, f.mSavedViewState);
Dianne Hackbornb46ed762011-06-02 18:33:15 -07002692 }
Adam Powell78fed9b2011-11-07 10:45:34 -08002693 if (!f.mUserVisibleHint) {
Jake Wharton258029e2012-04-22 17:17:01 -04002694 if (result == null) {
2695 result = new Bundle();
2696 }
Adam Powell78fed9b2011-11-07 10:45:34 -08002697 // Only add this if it's not the default value
2698 result.putBoolean(FragmentManagerImpl.USER_VISIBLE_HINT_TAG, f.mUserVisibleHint);
2699 }
Dianne Hackbornb46ed762011-06-02 18:33:15 -07002700
2701 return result;
2702 }
2703
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002704 Parcelable saveAllState() {
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08002705 // Make sure all pending operations have now been executed to get
2706 // our state update-to-date.
George Mount86bfc662016-07-12 16:06:06 -07002707 forcePostponedTransactions();
2708 endAnimatingAwayFragments();
Dianne Hackborn3a57fb92010-11-15 17:58:52 -08002709 execPendingActions();
2710
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07002711 mStateSaved = true;
George Mountf804d6a2017-04-05 12:30:17 -07002712 mSavedNonConfig = null;
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07002713
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07002714 if (mActive == null || mActive.size() <= 0) {
2715 return null;
2716 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002717
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07002718 // First collect all active fragments.
2719 int N = mActive.size();
2720 FragmentState[] active = new FragmentState[N];
2721 boolean haveFragments = false;
2722 for (int i=0; i<N; i++) {
George Mount838166d2017-03-23 14:23:29 -07002723 Fragment f = mActive.valueAt(i);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07002724 if (f != null) {
Dianne Hackborn61af8a82012-05-30 16:38:30 -07002725 if (f.mIndex < 0) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07002726 throwException(new IllegalStateException(
2727 "Failure saving state: active " + f
2728 + " has cleared index: " + f.mIndex));
Dianne Hackborn61af8a82012-05-30 16:38:30 -07002729 }
2730
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07002731 haveFragments = true;
Dianne Hackborn61af8a82012-05-30 16:38:30 -07002732
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07002733 FragmentState fs = new FragmentState(f);
2734 active[i] = fs;
2735
Dianne Hackborn625ac272010-09-17 18:29:22 -07002736 if (f.mState > Fragment.INITIALIZING && fs.mSavedFragmentState == null) {
Dianne Hackbornb46ed762011-06-02 18:33:15 -07002737 fs.mSavedFragmentState = saveFragmentBasicState(f);
Dianne Hackborn625ac272010-09-17 18:29:22 -07002738
2739 if (f.mTarget != null) {
Dianne Hackborn5d9d03a2011-01-24 13:15:09 -08002740 if (f.mTarget.mIndex < 0) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07002741 throwException(new IllegalStateException(
2742 "Failure saving state: " + f
2743 + " has target not in fragment manager: " + f.mTarget));
Dianne Hackborn5d9d03a2011-01-24 13:15:09 -08002744 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07002745 if (fs.mSavedFragmentState == null) {
2746 fs.mSavedFragmentState = new Bundle();
2747 }
Dianne Hackborn625ac272010-09-17 18:29:22 -07002748 putFragment(fs.mSavedFragmentState,
2749 FragmentManagerImpl.TARGET_STATE_TAG, f.mTarget);
2750 if (f.mTargetRequestCode != 0) {
2751 fs.mSavedFragmentState.putInt(
2752 FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG,
2753 f.mTargetRequestCode);
2754 }
Dianne Hackborndef15372010-08-15 12:43:52 -07002755 }
Dianne Hackborndef15372010-08-15 12:43:52 -07002756
Dianne Hackborn625ac272010-09-17 18:29:22 -07002757 } else {
2758 fs.mSavedFragmentState = f.mSavedFragmentState;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07002759 }
2760
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07002761 if (DEBUG) Log.v(TAG, "Saved state of " + f + ": "
2762 + fs.mSavedFragmentState);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07002763 }
2764 }
2765
2766 if (!haveFragments) {
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07002767 if (DEBUG) Log.v(TAG, "saveAllState: no fragments!");
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002768 return null;
2769 }
2770
2771 int[] added = null;
2772 BackStackState[] backStack = null;
2773
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07002774 // Build list of currently added fragments.
George Mount7cdd49a2017-05-22 16:21:09 -07002775 N = mAdded.size();
2776 if (N > 0) {
2777 added = new int[N];
2778 for (int i=0; i<N; i++) {
2779 added[i] = mAdded.get(i).mIndex;
2780 if (added[i] < 0) {
2781 throwException(new IllegalStateException(
2782 "Failure saving state: active " + mAdded.get(i)
2783 + " has cleared index: " + added[i]));
Dianne Hackborn625ac272010-09-17 18:29:22 -07002784 }
George Mount7cdd49a2017-05-22 16:21:09 -07002785 if (DEBUG) Log.v(TAG, "saveAllState: adding fragment #" + i
2786 + ": " + mAdded.get(i));
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002787 }
2788 }
George Mount7cdd49a2017-05-22 16:21:09 -07002789
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002790 // Now save back stack.
2791 if (mBackStack != null) {
2792 N = mBackStack.size();
2793 if (N > 0) {
2794 backStack = new BackStackState[N];
2795 for (int i=0; i<N; i++) {
2796 backStack[i] = new BackStackState(this, mBackStack.get(i));
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07002797 if (DEBUG) Log.v(TAG, "saveAllState: adding back stack #" + i
2798 + ": " + mBackStack.get(i));
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002799 }
2800 }
2801 }
2802
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002803 FragmentManagerState fms = new FragmentManagerState();
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07002804 fms.mActive = active;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002805 fms.mAdded = added;
2806 fms.mBackStack = backStack;
George Mount838166d2017-03-23 14:23:29 -07002807 fms.mNextFragmentIndex = mNextFragmentIndex;
Adam Powell5f3a05c2017-01-27 16:51:03 -08002808 if (mPrimaryNav != null) {
2809 fms.mPrimaryNavActiveIndex = mPrimaryNav.mIndex;
2810 }
George Mountf804d6a2017-04-05 12:30:17 -07002811 saveNonConfig();
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002812 return fms;
2813 }
2814
Adam Powell44ba79e2016-02-04 16:20:37 -08002815 void restoreAllState(Parcelable state, FragmentManagerNonConfig nonConfig) {
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002816 // If there is no saved state at all, then there can not be
2817 // any nonConfig fragments either, so that is that.
2818 if (state == null) return;
2819 FragmentManagerState fms = (FragmentManagerState)state;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07002820 if (fms.mActive == null) return;
Adam Powell44ba79e2016-02-04 16:20:37 -08002821
2822 List<FragmentManagerNonConfig> childNonConfigs = null;
2823
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07002824 // First re-attach any non-config instances we are retaining back
2825 // to their saved state, so we don't try to instantiate them again.
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002826 if (nonConfig != null) {
Adam Powell44ba79e2016-02-04 16:20:37 -08002827 List<Fragment> nonConfigFragments = nonConfig.getFragments();
2828 childNonConfigs = nonConfig.getChildNonConfigs();
2829 final int count = nonConfigFragments != null ? nonConfigFragments.size() : 0;
2830 for (int i = 0; i < count; i++) {
2831 Fragment f = nonConfigFragments.get(i);
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07002832 if (DEBUG) Log.v(TAG, "restoreAllState: re-attaching retained " + f);
George Mount5dd7c9a2017-03-29 14:56:05 -07002833 int index = 0; // index of f in fms.mActive
2834 while (index < fms.mActive.length && fms.mActive[index].mIndex != f.mIndex) {
2835 index++;
2836 }
2837 if (index == fms.mActive.length) {
2838 throwException(new IllegalStateException("Could not find active fragment "
2839 + "with index " + f.mIndex));
2840 }
2841 FragmentState fs = fms.mActive[index];
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002842 fs.mInstance = f;
2843 f.mSavedViewState = null;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07002844 f.mBackStackNesting = 0;
Dianne Hackborn625ac272010-09-17 18:29:22 -07002845 f.mInLayout = false;
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07002846 f.mAdded = false;
Dianne Hackbornf9302322011-06-14 18:36:14 -07002847 f.mTarget = null;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002848 if (fs.mSavedFragmentState != null) {
Todd Kennedya5fc6f02015-04-14 18:22:54 -07002849 fs.mSavedFragmentState.setClassLoader(mHost.getContext().getClassLoader());
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002850 f.mSavedViewState = fs.mSavedFragmentState.getSparseParcelableArray(
Dianne Hackborndef15372010-08-15 12:43:52 -07002851 FragmentManagerImpl.VIEW_STATE_TAG);
Craig Mautner33acfbe2014-06-28 14:00:53 -07002852 f.mSavedFragmentState = fs.mSavedFragmentState;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002853 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002854 }
2855 }
2856
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07002857 // Build the full list of active fragments, instantiating them from
2858 // their saved state.
George Mount838166d2017-03-23 14:23:29 -07002859 mActive = new SparseArray<>(fms.mActive.length);
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07002860 for (int i=0; i<fms.mActive.length; i++) {
2861 FragmentState fs = fms.mActive[i];
2862 if (fs != null) {
Adam Powell44ba79e2016-02-04 16:20:37 -08002863 FragmentManagerNonConfig childNonConfig = null;
2864 if (childNonConfigs != null && i < childNonConfigs.size()) {
2865 childNonConfig = childNonConfigs.get(i);
2866 }
Jason Monkb2852ca2017-01-09 15:12:37 -05002867 Fragment f = fs.instantiate(mHost, mContainer, mParent, childNonConfig);
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07002868 if (DEBUG) Log.v(TAG, "restoreAllState: active #" + i + ": " + f);
George Mount838166d2017-03-23 14:23:29 -07002869 mActive.put(f.mIndex, f);
Dianne Hackborn30d71892010-12-11 10:37:55 -08002870 // Now that the fragment is instantiated (or came from being
2871 // retained above), clear mInstance in case we end up re-restoring
2872 // from this FragmentState again.
2873 fs.mInstance = null;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002874 }
2875 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07002876
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07002877 // Update the target of all retained fragments.
2878 if (nonConfig != null) {
Adam Powell44ba79e2016-02-04 16:20:37 -08002879 List<Fragment> nonConfigFragments = nonConfig.getFragments();
2880 final int count = nonConfigFragments != null ? nonConfigFragments.size() : 0;
2881 for (int i = 0; i < count; i++) {
2882 Fragment f = nonConfigFragments.get(i);
Dianne Hackbornf9302322011-06-14 18:36:14 -07002883 if (f.mTargetIndex >= 0) {
George Mount838166d2017-03-23 14:23:29 -07002884 f.mTarget = mActive.get(f.mTargetIndex);
2885 if (f.mTarget == null) {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07002886 Log.w(TAG, "Re-attaching retained fragment " + f
Dianne Hackbornf9302322011-06-14 18:36:14 -07002887 + " target no longer exists: " + f.mTargetIndex);
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07002888 f.mTarget = null;
2889 }
2890 }
2891 }
2892 }
2893
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07002894 // Build the list of currently added fragments.
George Mount7cdd49a2017-05-22 16:21:09 -07002895 mAdded.clear();
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07002896 if (fms.mAdded != null) {
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07002897 for (int i=0; i<fms.mAdded.length; i++) {
2898 Fragment f = mActive.get(fms.mAdded[i]);
2899 if (f == null) {
Dianne Hackborn4702a852012-08-17 15:18:29 -07002900 throwException(new IllegalStateException(
2901 "No instantiated fragment for index #" + fms.mAdded[i]));
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07002902 }
2903 f.mAdded = true;
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07002904 if (DEBUG) Log.v(TAG, "restoreAllState: added #" + i + ": " + f);
2905 if (mAdded.contains(f)) {
2906 throw new IllegalStateException("Already added!");
2907 }
George Mountc7146be2017-03-29 14:13:03 +00002908 synchronized (mAdded) {
2909 mAdded.add(f);
2910 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07002911 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07002912 }
2913
2914 // Build the back stack.
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002915 if (fms.mBackStack != null) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07002916 mBackStack = new ArrayList<BackStackRecord>(fms.mBackStack.length);
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002917 for (int i=0; i<fms.mBackStack.length; i++) {
Dianne Hackbornc6669ca2010-09-16 01:33:24 -07002918 BackStackRecord bse = fms.mBackStack[i].instantiate(this);
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07002919 if (DEBUG) {
2920 Log.v(TAG, "restoreAllState: back stack #" + i
Dianne Hackbornb7a2e472010-08-12 16:20:42 -07002921 + " (index " + bse.mIndex + "): " + bse);
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07002922 LogWriter logw = new LogWriter(Log.VERBOSE, TAG);
Dianne Hackborn8c841092013-06-24 13:46:13 -07002923 PrintWriter pw = new FastPrintWriter(logw, false, 1024);
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07002924 bse.dump(" ", pw, false);
Dianne Hackborn8c841092013-06-24 13:46:13 -07002925 pw.flush();
Dianne Hackbornf43a33c2012-09-27 00:48:11 -07002926 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002927 mBackStack.add(bse);
Dianne Hackborndd913a52010-07-22 12:17:04 -07002928 if (bse.mIndex >= 0) {
2929 setBackStackIndex(bse.mIndex, bse);
2930 }
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002931 }
Dianne Hackborn6e8304e2010-05-14 00:42:53 -07002932 } else {
2933 mBackStack = null;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002934 }
Adam Powell5f3a05c2017-01-27 16:51:03 -08002935
2936 if (fms.mPrimaryNavActiveIndex >= 0) {
2937 mPrimaryNav = mActive.get(fms.mPrimaryNavActiveIndex);
2938 }
George Mount838166d2017-03-23 14:23:29 -07002939
2940 mNextFragmentIndex = fms.mNextFragmentIndex;
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002941 }
George Mount838166d2017-03-23 14:23:29 -07002942
2943 /**
2944 * To prevent list modification errors, mActive sets values to null instead of
2945 * removing them when the Fragment becomes inactive. This cleans up the list at the
2946 * end of executing the transactions.
2947 */
2948 private void burpActive() {
2949 if (mActive != null) {
2950 for (int i = mActive.size() - 1; i >= 0; i--) {
2951 if (mActive.valueAt(i) == null) {
2952 mActive.delete(mActive.keyAt(i));
2953 }
2954 }
2955 }
2956 }
2957
Todd Kennedya5fc6f02015-04-14 18:22:54 -07002958 public void attachController(FragmentHostCallback<?> host, FragmentContainer container,
2959 Fragment parent) {
2960 if (mHost != null) throw new IllegalStateException("Already attached");
2961 mHost = host;
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07002962 mContainer = container;
2963 mParent = parent;
George Mountf1d88e62017-03-13 10:47:57 -07002964 mAllowOldReentrantBehavior = getTargetSdk() <= Build.VERSION_CODES.N_MR1;
Dianne Hackborn2dedce62010-04-15 14:45:25 -07002965 }
George Mountf1d88e62017-03-13 10:47:57 -07002966
2967 /**
2968 * @return the target SDK of the FragmentManager's application info. If the
2969 * FragmentManager has been torn down, then 0 is returned.
2970 */
2971 int getTargetSdk() {
2972 if (mHost != null) {
2973 Context context = mHost.getContext();
2974 if (context != null) {
2975 ApplicationInfo info = context.getApplicationInfo();
2976 if (info != null) {
2977 return info.targetSdkVersion;
2978 }
2979 }
2980 }
2981 return 0;
2982 }
2983
Mathew Inwood61e8ae62018-08-14 14:17:44 +01002984 @UnsupportedAppUsage
Dianne Hackbornfb3cffe2010-10-25 17:08:56 -07002985 public void noteStateNotSaved() {
George Mountf804d6a2017-04-05 12:30:17 -07002986 mSavedNonConfig = null;
Dianne Hackbornfb3cffe2010-10-25 17:08:56 -07002987 mStateSaved = false;
George Mount7cdd49a2017-05-22 16:21:09 -07002988 final int addedCount = mAdded.size();
George Mount74af0762017-04-04 17:25:15 -07002989 for (int i = 0; i < addedCount; i++) {
2990 Fragment fragment = mAdded.get(i);
2991 if (fragment != null) {
2992 fragment.noteStateNotSaved();
2993 }
2994 }
Dianne Hackbornfb3cffe2010-10-25 17:08:56 -07002995 }
George Mount74af0762017-04-04 17:25:15 -07002996
Dianne Hackbornb4bc78b2010-05-12 18:59:50 -07002997 public void dispatchCreate() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07002998 mStateSaved = false;
George Mountf1d88e62017-03-13 10:47:57 -07002999 dispatchMoveToState(Fragment.CREATED);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07003000 }
3001
Dianne Hackbornc8017682010-07-06 13:34:38 -07003002 public void dispatchActivityCreated() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07003003 mStateSaved = false;
George Mountf1d88e62017-03-13 10:47:57 -07003004 dispatchMoveToState(Fragment.ACTIVITY_CREATED);
Dianne Hackbornc8017682010-07-06 13:34:38 -07003005 }
3006
Dianne Hackborn2dedce62010-04-15 14:45:25 -07003007 public void dispatchStart() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07003008 mStateSaved = false;
George Mountf1d88e62017-03-13 10:47:57 -07003009 dispatchMoveToState(Fragment.STARTED);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07003010 }
3011
3012 public void dispatchResume() {
Dianne Hackborn3e449ce2010-09-11 20:52:31 -07003013 mStateSaved = false;
George Mountf1d88e62017-03-13 10:47:57 -07003014 dispatchMoveToState(Fragment.RESUMED);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07003015 }
3016
3017 public void dispatchPause() {
George Mountf1d88e62017-03-13 10:47:57 -07003018 dispatchMoveToState(Fragment.STARTED);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07003019 }
3020
3021 public void dispatchStop() {
George Mountf1d88e62017-03-13 10:47:57 -07003022 dispatchMoveToState(Fragment.STOPPED);
Dianne Hackborn2dedce62010-04-15 14:45:25 -07003023 }
3024
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07003025 public void dispatchDestroyView() {
George Mountf1d88e62017-03-13 10:47:57 -07003026 dispatchMoveToState(Fragment.CREATED);
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07003027 }
Dianne Hackborn1b8ecc52012-09-08 17:03:52 -07003028
Dianne Hackborn2dedce62010-04-15 14:45:25 -07003029 public void dispatchDestroy() {
Dianne Hackbornd173fa32010-12-23 13:58:22 -08003030 mDestroyed = true;
Dianne Hackbornc6938232011-07-21 16:25:26 -07003031 execPendingActions();
George Mountf1d88e62017-03-13 10:47:57 -07003032 dispatchMoveToState(Fragment.INITIALIZING);
Todd Kennedya5fc6f02015-04-14 18:22:54 -07003033 mHost = null;
Dianne Hackborn62bea2f2012-09-04 18:48:15 -07003034 mContainer = null;
3035 mParent = null;
Dianne Hackborn2dedce62010-04-15 14:45:25 -07003036 }
Wale Ogunwale7c796812016-01-29 21:13:50 -08003037
George Mountf1d88e62017-03-13 10:47:57 -07003038 /**
3039 * This method is called by dispatch* methods to change the FragmentManager's state.
3040 * It calls moveToState directly if the target SDK is older than O. Otherwise, it sets and
3041 * clears mExecutingActions to ensure that there is no reentrancy while the
3042 * FragmentManager is changing state.
3043 *
3044 * @param state The new state of the FragmentManager.
3045 */
3046 private void dispatchMoveToState(int state) {
3047 if (mAllowOldReentrantBehavior) {
3048 moveToState(state, false);
3049 } else {
3050 try {
3051 mExecutingActions = true;
3052 moveToState(state, false);
3053 } finally {
3054 mExecutingActions = false;
3055 }
3056 }
George Mount46d624d2017-04-17 15:46:23 -07003057 execPendingActions();
George Mountf1d88e62017-03-13 10:47:57 -07003058 }
3059
Winson Chung5af42fc2017-03-24 17:11:33 -07003060 /**
3061 * @deprecated use {@link #dispatchMultiWindowModeChanged(boolean, Configuration)}
3062 */
3063 @Deprecated
Andrii Kulian933076d2016-03-29 17:04:42 -07003064 public void dispatchMultiWindowModeChanged(boolean isInMultiWindowMode) {
Wale Ogunwale7c796812016-01-29 21:13:50 -08003065 for (int i = mAdded.size() - 1; i >= 0; --i) {
3066 final Fragment f = mAdded.get(i);
3067 if (f != null) {
Andrii Kulian933076d2016-03-29 17:04:42 -07003068 f.performMultiWindowModeChanged(isInMultiWindowMode);
Wale Ogunwale7c796812016-01-29 21:13:50 -08003069 }
3070 }
3071 }
3072
Winson Chung5af42fc2017-03-24 17:11:33 -07003073 public void dispatchMultiWindowModeChanged(boolean isInMultiWindowMode,
3074 Configuration newConfig) {
Winson Chung5af42fc2017-03-24 17:11:33 -07003075 for (int i = mAdded.size() - 1; i >= 0; --i) {
3076 final Fragment f = mAdded.get(i);
3077 if (f != null) {
3078 f.performMultiWindowModeChanged(isInMultiWindowMode, newConfig);
3079 }
3080 }
3081 }
3082
3083 /**
3084 * @deprecated use {@link #dispatchPictureInPictureModeChanged(boolean, Configuration)}
3085 */
3086 @Deprecated
Andrii Kulian933076d2016-03-29 17:04:42 -07003087 public void dispatchPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
Wale Ogunwale7c796812016-01-29 21:13:50 -08003088 for (int i = mAdded.size() - 1; i >= 0; --i) {
3089 final Fragment f = mAdded.get(i);
3090 if (f != null) {
Andrii Kulian933076d2016-03-29 17:04:42 -07003091 f.performPictureInPictureModeChanged(isInPictureInPictureMode);
Wale Ogunwale7c796812016-01-29 21:13:50 -08003092 }
3093 }
3094 }
3095
Winson Chung5af42fc2017-03-24 17:11:33 -07003096 public void dispatchPictureInPictureModeChanged(boolean isInPictureInPictureMode,
3097 Configuration newConfig) {
Winson Chung5af42fc2017-03-24 17:11:33 -07003098 for (int i = mAdded.size() - 1; i >= 0; --i) {
3099 final Fragment f = mAdded.get(i);
3100 if (f != null) {
3101 f.performPictureInPictureModeChanged(isInPictureInPictureMode, newConfig);
3102 }
3103 }
3104 }
3105
Dianne Hackborn9d071802010-12-08 14:49:15 -08003106 public void dispatchConfigurationChanged(Configuration newConfig) {
George Mount7cdd49a2017-05-22 16:21:09 -07003107 for (int i = 0; i < mAdded.size(); i++) {
3108 Fragment f = mAdded.get(i);
3109 if (f != null) {
3110 f.performConfigurationChanged(newConfig);
Dianne Hackborn9d071802010-12-08 14:49:15 -08003111 }
3112 }
3113 }
3114
3115 public void dispatchLowMemory() {
George Mount7cdd49a2017-05-22 16:21:09 -07003116 for (int i = 0; i < mAdded.size(); i++) {
3117 Fragment f = mAdded.get(i);
3118 if (f != null) {
3119 f.performLowMemory();
Dianne Hackborn9d071802010-12-08 14:49:15 -08003120 }
3121 }
3122 }
3123
Dianne Hackbornc68c9132011-07-29 01:25:18 -07003124 public void dispatchTrimMemory(int level) {
George Mount7cdd49a2017-05-22 16:21:09 -07003125 for (int i = 0; i < mAdded.size(); i++) {
3126 Fragment f = mAdded.get(i);
3127 if (f != null) {
3128 f.performTrimMemory(level);
Dianne Hackbornc68c9132011-07-29 01:25:18 -07003129 }
3130 }
3131 }
3132
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07003133 public boolean dispatchCreateOptionsMenu(Menu menu, MenuInflater inflater) {
George Mountf558fa32017-07-11 09:58:35 -07003134 if (mCurState < Fragment.CREATED) {
3135 return false;
3136 }
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07003137 boolean show = false;
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07003138 ArrayList<Fragment> newMenus = null;
George Mount7cdd49a2017-05-22 16:21:09 -07003139 for (int i = 0; i < mAdded.size(); i++) {
3140 Fragment f = mAdded.get(i);
3141 if (f != null) {
3142 if (f.performCreateOptionsMenu(menu, inflater)) {
3143 show = true;
3144 if (newMenus == null) {
3145 newMenus = new ArrayList<Fragment>();
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07003146 }
George Mount7cdd49a2017-05-22 16:21:09 -07003147 newMenus.add(f);
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07003148 }
3149 }
3150 }
George Mount7cdd49a2017-05-22 16:21:09 -07003151
Dianne Hackborn8eb2e242010-11-01 12:31:24 -07003152 if (mCreatedMenus != null) {
3153 for (int i=0; i<mCreatedMenus.size(); i++) {
3154 Fragment f = mCreatedMenus.get(i);
3155 if (newMenus == null || !newMenus.contains(f)) {
3156 f.onDestroyOptionsMenu();
3157 }
3158 }
3159 }
3160
3161 mCreatedMenus = newMenus;
3162
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07003163 return show;
3164 }
3165
3166 public boolean dispatchPrepareOptionsMenu(Menu menu) {
George Mountf558fa32017-07-11 09:58:35 -07003167 if (mCurState < Fragment.CREATED) {
3168 return false;
3169 }
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07003170 boolean show = false;
George Mount7cdd49a2017-05-22 16:21:09 -07003171 for (int i = 0; i < mAdded.size(); i++) {
3172 Fragment f = mAdded.get(i);
3173 if (f != null) {
3174 if (f.performPrepareOptionsMenu(menu)) {
3175 show = true;
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07003176 }
3177 }
3178 }
3179 return show;
3180 }
3181
3182 public boolean dispatchOptionsItemSelected(MenuItem item) {
George Mountf558fa32017-07-11 09:58:35 -07003183 if (mCurState < Fragment.CREATED) {
3184 return false;
3185 }
George Mount7cdd49a2017-05-22 16:21:09 -07003186 for (int i = 0; i < mAdded.size(); i++) {
3187 Fragment f = mAdded.get(i);
3188 if (f != null) {
3189 if (f.performOptionsItemSelected(item)) {
3190 return true;
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07003191 }
3192 }
3193 }
3194 return false;
3195 }
3196
Dianne Hackborn5ddd1272010-06-12 10:15:28 -07003197 public boolean dispatchContextItemSelected(MenuItem item) {
George Mountf558fa32017-07-11 09:58:35 -07003198 if (mCurState < Fragment.CREATED) {
3199 return false;
3200 }
George Mount7cdd49a2017-05-22 16:21:09 -07003201 for (int i = 0; i < mAdded.size(); i++) {
3202 Fragment f = mAdded.get(i);
3203 if (f != null) {
3204 if (f.performContextItemSelected(item)) {
3205 return true;
Dianne Hackborn5ddd1272010-06-12 10:15:28 -07003206 }
3207 }
3208 }
3209 return false;
3210 }
3211
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07003212 public void dispatchOptionsMenuClosed(Menu menu) {
George Mountf558fa32017-07-11 09:58:35 -07003213 if (mCurState < Fragment.CREATED) {
3214 return;
3215 }
George Mount7cdd49a2017-05-22 16:21:09 -07003216 for (int i = 0; i < mAdded.size(); i++) {
3217 Fragment f = mAdded.get(i);
3218 if (f != null) {
3219 f.performOptionsMenuClosed(menu);
Dianne Hackbornb31e84bc2010-06-08 18:04:35 -07003220 }
3221 }
3222 }
Adam Powellf0f5fff2011-08-01 13:42:50 -07003223
Aurimas Liutikas221f15d42017-03-30 16:32:58 -07003224 @SuppressWarnings("ReferenceEquality")
Adam Powell5f3a05c2017-01-27 16:51:03 -08003225 public void setPrimaryNavigationFragment(Fragment f) {
George Mount838166d2017-03-23 14:23:29 -07003226 if (f != null && (mActive.get(f.mIndex) != f
3227 || (f.mHost != null && f.getFragmentManager() != this))) {
Adam Powell5f3a05c2017-01-27 16:51:03 -08003228 throw new IllegalArgumentException("Fragment " + f
3229 + " is not an active fragment of FragmentManager " + this);
3230 }
3231 mPrimaryNav = f;
3232 }
3233
3234 public Fragment getPrimaryNavigationFragment() {
3235 return mPrimaryNav;
3236 }
3237
Adam Powell38c67ff2016-10-28 10:24:40 -07003238 public void registerFragmentLifecycleCallbacks(FragmentLifecycleCallbacks cb,
3239 boolean recursive) {
Aurimas Liutikas8d5d55a2017-06-07 14:11:10 -07003240 mLifecycleCallbacks.add(new Pair<>(cb, recursive));
Adam Powell38c67ff2016-10-28 10:24:40 -07003241 }
3242
3243 public void unregisterFragmentLifecycleCallbacks(FragmentLifecycleCallbacks cb) {
Adam Powell38c67ff2016-10-28 10:24:40 -07003244 synchronized (mLifecycleCallbacks) {
3245 for (int i = 0, N = mLifecycleCallbacks.size(); i < N; i++) {
3246 if (mLifecycleCallbacks.get(i).first == cb) {
3247 mLifecycleCallbacks.remove(i);
3248 break;
3249 }
3250 }
3251 }
3252 }
3253
3254 void dispatchOnFragmentPreAttached(Fragment f, Context context, boolean onlyRecursive) {
3255 if (mParent != null) {
3256 FragmentManager parentManager = mParent.getFragmentManager();
3257 if (parentManager instanceof FragmentManagerImpl) {
3258 ((FragmentManagerImpl) parentManager)
3259 .dispatchOnFragmentPreAttached(f, context, true);
3260 }
3261 }
Adam Powell38c67ff2016-10-28 10:24:40 -07003262 for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
3263 if (!onlyRecursive || p.second) {
3264 p.first.onFragmentPreAttached(this, f, context);
3265 }
3266 }
3267 }
3268
3269 void dispatchOnFragmentAttached(Fragment f, Context context, boolean onlyRecursive) {
3270 if (mParent != null) {
3271 FragmentManager parentManager = mParent.getFragmentManager();
3272 if (parentManager instanceof FragmentManagerImpl) {
3273 ((FragmentManagerImpl) parentManager)
3274 .dispatchOnFragmentAttached(f, context, true);
3275 }
3276 }
Adam Powell38c67ff2016-10-28 10:24:40 -07003277 for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
3278 if (!onlyRecursive || p.second) {
3279 p.first.onFragmentAttached(this, f, context);
3280 }
3281 }
3282 }
3283
Adam Powell10d69ac2017-04-25 15:24:49 -07003284 void dispatchOnFragmentPreCreated(Fragment f, Bundle savedInstanceState,
3285 boolean onlyRecursive) {
3286 if (mParent != null) {
3287 FragmentManager parentManager = mParent.getFragmentManager();
3288 if (parentManager instanceof FragmentManagerImpl) {
3289 ((FragmentManagerImpl) parentManager)
3290 .dispatchOnFragmentPreCreated(f, savedInstanceState, true);
3291 }
3292 }
Adam Powell10d69ac2017-04-25 15:24:49 -07003293 for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
3294 if (!onlyRecursive || p.second) {
3295 p.first.onFragmentPreCreated(this, f, savedInstanceState);
3296 }
3297 }
3298 }
3299
Adam Powell38c67ff2016-10-28 10:24:40 -07003300 void dispatchOnFragmentCreated(Fragment f, Bundle savedInstanceState, boolean onlyRecursive) {
3301 if (mParent != null) {
3302 FragmentManager parentManager = mParent.getFragmentManager();
3303 if (parentManager instanceof FragmentManagerImpl) {
3304 ((FragmentManagerImpl) parentManager)
3305 .dispatchOnFragmentCreated(f, savedInstanceState, true);
3306 }
3307 }
Adam Powell38c67ff2016-10-28 10:24:40 -07003308 for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
3309 if (!onlyRecursive || p.second) {
3310 p.first.onFragmentCreated(this, f, savedInstanceState);
3311 }
3312 }
3313 }
3314
3315 void dispatchOnFragmentActivityCreated(Fragment f, Bundle savedInstanceState,
3316 boolean onlyRecursive) {
3317 if (mParent != null) {
3318 FragmentManager parentManager = mParent.getFragmentManager();
3319 if (parentManager instanceof FragmentManagerImpl) {
3320 ((FragmentManagerImpl) parentManager)
3321 .dispatchOnFragmentActivityCreated(f, savedInstanceState, true);
3322 }
3323 }
Adam Powell38c67ff2016-10-28 10:24:40 -07003324 for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
3325 if (!onlyRecursive || p.second) {
3326 p.first.onFragmentActivityCreated(this, f, savedInstanceState);
3327 }
3328 }
3329 }
3330
3331 void dispatchOnFragmentViewCreated(Fragment f, View v, Bundle savedInstanceState,
3332 boolean onlyRecursive) {
3333 if (mParent != null) {
3334 FragmentManager parentManager = mParent.getFragmentManager();
3335 if (parentManager instanceof FragmentManagerImpl) {
3336 ((FragmentManagerImpl) parentManager)
3337 .dispatchOnFragmentViewCreated(f, v, savedInstanceState, true);
3338 }
3339 }
Adam Powell38c67ff2016-10-28 10:24:40 -07003340 for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
3341 if (!onlyRecursive || p.second) {
3342 p.first.onFragmentViewCreated(this, f, v, savedInstanceState);
3343 }
3344 }
3345 }
3346
3347 void dispatchOnFragmentStarted(Fragment f, boolean onlyRecursive) {
3348 if (mParent != null) {
3349 FragmentManager parentManager = mParent.getFragmentManager();
3350 if (parentManager instanceof FragmentManagerImpl) {
3351 ((FragmentManagerImpl) parentManager)
3352 .dispatchOnFragmentStarted(f, true);
3353 }
3354 }
Adam Powell38c67ff2016-10-28 10:24:40 -07003355 for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
3356 if (!onlyRecursive || p.second) {
3357 p.first.onFragmentStarted(this, f);
3358 }
3359 }
3360 }
3361
3362 void dispatchOnFragmentResumed(Fragment f, boolean onlyRecursive) {
3363 if (mParent != null) {
3364 FragmentManager parentManager = mParent.getFragmentManager();
3365 if (parentManager instanceof FragmentManagerImpl) {
3366 ((FragmentManagerImpl) parentManager)
3367 .dispatchOnFragmentResumed(f, true);
3368 }
3369 }
Adam Powell38c67ff2016-10-28 10:24:40 -07003370 for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
3371 if (!onlyRecursive || p.second) {
3372 p.first.onFragmentResumed(this, f);
3373 }
3374 }
3375 }
3376
3377 void dispatchOnFragmentPaused(Fragment f, boolean onlyRecursive) {
3378 if (mParent != null) {
3379 FragmentManager parentManager = mParent.getFragmentManager();
3380 if (parentManager instanceof FragmentManagerImpl) {
3381 ((FragmentManagerImpl) parentManager)
3382 .dispatchOnFragmentPaused(f, true);
3383 }
3384 }
Adam Powell38c67ff2016-10-28 10:24:40 -07003385 for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
3386 if (!onlyRecursive || p.second) {
3387 p.first.onFragmentPaused(this, f);
3388 }
3389 }
3390 }
3391
3392 void dispatchOnFragmentStopped(Fragment f, boolean onlyRecursive) {
3393 if (mParent != null) {
3394 FragmentManager parentManager = mParent.getFragmentManager();
3395 if (parentManager instanceof FragmentManagerImpl) {
3396 ((FragmentManagerImpl) parentManager)
3397 .dispatchOnFragmentStopped(f, true);
3398 }
3399 }
Adam Powell38c67ff2016-10-28 10:24:40 -07003400 for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
3401 if (!onlyRecursive || p.second) {
3402 p.first.onFragmentStopped(this, f);
3403 }
3404 }
3405 }
3406
3407 void dispatchOnFragmentSaveInstanceState(Fragment f, Bundle outState, boolean onlyRecursive) {
3408 if (mParent != null) {
3409 FragmentManager parentManager = mParent.getFragmentManager();
3410 if (parentManager instanceof FragmentManagerImpl) {
3411 ((FragmentManagerImpl) parentManager)
3412 .dispatchOnFragmentSaveInstanceState(f, outState, true);
3413 }
3414 }
Adam Powell38c67ff2016-10-28 10:24:40 -07003415 for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
3416 if (!onlyRecursive || p.second) {
3417 p.first.onFragmentSaveInstanceState(this, f, outState);
3418 }
3419 }
3420 }
3421
3422 void dispatchOnFragmentViewDestroyed(Fragment f, boolean onlyRecursive) {
3423 if (mParent != null) {
3424 FragmentManager parentManager = mParent.getFragmentManager();
3425 if (parentManager instanceof FragmentManagerImpl) {
3426 ((FragmentManagerImpl) parentManager)
3427 .dispatchOnFragmentViewDestroyed(f, true);
3428 }
3429 }
Adam Powell38c67ff2016-10-28 10:24:40 -07003430 for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
3431 if (!onlyRecursive || p.second) {
3432 p.first.onFragmentViewDestroyed(this, f);
3433 }
3434 }
3435 }
3436
3437 void dispatchOnFragmentDestroyed(Fragment f, boolean onlyRecursive) {
3438 if (mParent != null) {
3439 FragmentManager parentManager = mParent.getFragmentManager();
3440 if (parentManager instanceof FragmentManagerImpl) {
3441 ((FragmentManagerImpl) parentManager)
3442 .dispatchOnFragmentDestroyed(f, true);
3443 }
3444 }
Adam Powell38c67ff2016-10-28 10:24:40 -07003445 for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
3446 if (!onlyRecursive || p.second) {
3447 p.first.onFragmentDestroyed(this, f);
3448 }
3449 }
3450 }
3451
3452 void dispatchOnFragmentDetached(Fragment f, boolean onlyRecursive) {
3453 if (mParent != null) {
3454 FragmentManager parentManager = mParent.getFragmentManager();
3455 if (parentManager instanceof FragmentManagerImpl) {
3456 ((FragmentManagerImpl) parentManager)
3457 .dispatchOnFragmentDetached(f, true);
3458 }
3459 }
Adam Powell38c67ff2016-10-28 10:24:40 -07003460 for (Pair<FragmentLifecycleCallbacks, Boolean> p : mLifecycleCallbacks) {
3461 if (!onlyRecursive || p.second) {
3462 p.first.onFragmentDetached(this, f);
3463 }
3464 }
3465 }
3466
Adam Powellf0f5fff2011-08-01 13:42:50 -07003467 @Override
3468 public void invalidateOptionsMenu() {
Todd Kennedya5fc6f02015-04-14 18:22:54 -07003469 if (mHost != null && mCurState == Fragment.RESUMED) {
3470 mHost.onInvalidateOptionsMenu();
Adam Powellf0f5fff2011-08-01 13:42:50 -07003471 } else {
3472 mNeedMenuInvalidate = true;
3473 }
3474 }
3475
Dianne Hackbornf121be72010-05-06 14:10:32 -07003476 public static int reverseTransit(int transit) {
3477 int rev = 0;
3478 switch (transit) {
Chet Haase811ed1062010-08-06 10:38:15 -07003479 case FragmentTransaction.TRANSIT_FRAGMENT_OPEN:
3480 rev = FragmentTransaction.TRANSIT_FRAGMENT_CLOSE;
Dianne Hackbornf121be72010-05-06 14:10:32 -07003481 break;
Chet Haase811ed1062010-08-06 10:38:15 -07003482 case FragmentTransaction.TRANSIT_FRAGMENT_CLOSE:
3483 rev = FragmentTransaction.TRANSIT_FRAGMENT_OPEN;
Dianne Hackbornf121be72010-05-06 14:10:32 -07003484 break;
Dianne Hackborn327fbd22011-01-17 14:38:50 -08003485 case FragmentTransaction.TRANSIT_FRAGMENT_FADE:
3486 rev = FragmentTransaction.TRANSIT_FRAGMENT_FADE;
Chet Haase9ff82bf2010-10-05 14:30:51 -07003487 break;
Dianne Hackbornf121be72010-05-06 14:10:32 -07003488 }
3489 return rev;
3490
3491 }
3492
3493 public static int transitToStyleIndex(int transit, boolean enter) {
3494 int animAttr = -1;
3495 switch (transit) {
Chet Haase811ed1062010-08-06 10:38:15 -07003496 case FragmentTransaction.TRANSIT_FRAGMENT_OPEN:
Dianne Hackbornf121be72010-05-06 14:10:32 -07003497 animAttr = enter
Chet Haase811ed1062010-08-06 10:38:15 -07003498 ? com.android.internal.R.styleable.FragmentAnimation_fragmentOpenEnterAnimation
3499 : com.android.internal.R.styleable.FragmentAnimation_fragmentOpenExitAnimation;
Dianne Hackbornf121be72010-05-06 14:10:32 -07003500 break;
Chet Haase811ed1062010-08-06 10:38:15 -07003501 case FragmentTransaction.TRANSIT_FRAGMENT_CLOSE:
Dianne Hackbornf121be72010-05-06 14:10:32 -07003502 animAttr = enter
Chet Haase811ed1062010-08-06 10:38:15 -07003503 ? com.android.internal.R.styleable.FragmentAnimation_fragmentCloseEnterAnimation
3504 : com.android.internal.R.styleable.FragmentAnimation_fragmentCloseExitAnimation;
Dianne Hackbornf121be72010-05-06 14:10:32 -07003505 break;
Dianne Hackborn327fbd22011-01-17 14:38:50 -08003506 case FragmentTransaction.TRANSIT_FRAGMENT_FADE:
Chet Haase9ff82bf2010-10-05 14:30:51 -07003507 animAttr = enter
Dianne Hackborn327fbd22011-01-17 14:38:50 -08003508 ? com.android.internal.R.styleable.FragmentAnimation_fragmentFadeEnterAnimation
3509 : com.android.internal.R.styleable.FragmentAnimation_fragmentFadeExitAnimation;
Chet Haase9ff82bf2010-10-05 14:30:51 -07003510 break;
Dianne Hackbornf121be72010-05-06 14:10:32 -07003511 }
3512 return animAttr;
3513 }
Adam Powell371a8092014-06-20 12:51:12 -07003514
3515 @Override
3516 public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
3517 if (!"fragment".equals(name)) {
3518 return null;
3519 }
3520
3521 String fname = attrs.getAttributeValue(null, "class");
3522 TypedArray a =
3523 context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.Fragment);
3524 if (fname == null) {
3525 fname = a.getString(com.android.internal.R.styleable.Fragment_name);
3526 }
3527 int id = a.getResourceId(com.android.internal.R.styleable.Fragment_id, View.NO_ID);
3528 String tag = a.getString(com.android.internal.R.styleable.Fragment_tag);
3529 a.recycle();
3530
3531 int containerId = parent != null ? parent.getId() : 0;
3532 if (containerId == View.NO_ID && id == View.NO_ID && tag == null) {
3533 throw new IllegalArgumentException(attrs.getPositionDescription()
3534 + ": Must specify unique android:id, android:tag, or have a parent with"
3535 + " an id for " + fname);
3536 }
3537
3538 // If we restored from a previous state, we may already have
3539 // instantiated this fragment from the state and should use
3540 // that instance instead of making a new one.
3541 Fragment fragment = id != View.NO_ID ? findFragmentById(id) : null;
3542 if (fragment == null && tag != null) {
3543 fragment = findFragmentByTag(tag);
3544 }
3545 if (fragment == null && containerId != View.NO_ID) {
3546 fragment = findFragmentById(containerId);
3547 }
3548
3549 if (FragmentManagerImpl.DEBUG) Log.v(TAG, "onCreateView: id=0x"
3550 + Integer.toHexString(id) + " fname=" + fname
3551 + " existing=" + fragment);
3552 if (fragment == null) {
Jason Monkb2852ca2017-01-09 15:12:37 -05003553 fragment = mContainer.instantiate(context, fname, null);
Adam Powell371a8092014-06-20 12:51:12 -07003554 fragment.mFromLayout = true;
3555 fragment.mFragmentId = id != 0 ? id : containerId;
3556 fragment.mContainerId = containerId;
3557 fragment.mTag = tag;
3558 fragment.mInLayout = true;
3559 fragment.mFragmentManager = this;
Todd Kennedy0aa69b72015-08-31 14:10:04 -07003560 fragment.mHost = mHost;
Todd Kennedy434bd652015-05-04 12:29:50 -07003561 fragment.onInflate(mHost.getContext(), attrs, fragment.mSavedFragmentState);
Adam Powell371a8092014-06-20 12:51:12 -07003562 addFragment(fragment, true);
3563 } else if (fragment.mInLayout) {
3564 // A fragment already exists and it is not one we restored from
3565 // previous state.
3566 throw new IllegalArgumentException(attrs.getPositionDescription()
3567 + ": Duplicate id 0x" + Integer.toHexString(id)
3568 + ", tag " + tag + ", or parent id 0x" + Integer.toHexString(containerId)
3569 + " with another fragment for " + fname);
3570 } else {
3571 // This fragment was retained from a previous instance; get it
3572 // going now.
3573 fragment.mInLayout = true;
Todd Kennedyac0e6ca2015-10-19 12:48:55 -07003574 fragment.mHost = mHost;
Adam Powell371a8092014-06-20 12:51:12 -07003575 // If this fragment is newly instantiated (either right now, or
3576 // from last saved state), then give it the attributes to
3577 // initialize itself.
3578 if (!fragment.mRetaining) {
Todd Kennedy434bd652015-05-04 12:29:50 -07003579 fragment.onInflate(mHost.getContext(), attrs, fragment.mSavedFragmentState);
Adam Powell371a8092014-06-20 12:51:12 -07003580 }
3581 }
3582
3583 // If we haven't finished entering the CREATED state ourselves yet,
Adam Powellbb3aa342016-11-16 10:34:57 -08003584 // push the inflated child fragment along. This will ensureInflatedFragmentView
3585 // at the right phase of the lifecycle so that we will have mView populated
3586 // for compliant fragments below.
Adam Powell371a8092014-06-20 12:51:12 -07003587 if (mCurState < Fragment.CREATED && fragment.mFromLayout) {
3588 moveToState(fragment, Fragment.CREATED, 0, 0, false);
3589 } else {
3590 moveToState(fragment);
3591 }
3592
3593 if (fragment.mView == null) {
3594 throw new IllegalStateException("Fragment " + fname
3595 + " did not create a view.");
3596 }
3597 if (id != 0) {
3598 fragment.mView.setId(id);
3599 }
3600 if (fragment.mView.getTag() == null) {
3601 fragment.mView.setTag(tag);
3602 }
3603 return fragment.mView;
3604 }
3605
3606 @Override
3607 public View onCreateView(String name, Context context, AttributeSet attrs) {
3608 return null;
3609 }
3610
3611 LayoutInflater.Factory2 getLayoutInflaterFactory() {
3612 return this;
3613 }
George Mounteca8e222016-07-07 13:13:05 -07003614
3615 /**
3616 * An add or pop transaction to be scheduled for the UI thread.
3617 */
3618 interface OpGenerator {
3619 /**
3620 * Generate transactions to add to {@code records} and whether or not the transaction is
3621 * an add or pop to {@code isRecordPop}.
3622 *
3623 * records and isRecordPop must be added equally so that each transaction in records
3624 * matches the boolean for whether or not it is a pop in isRecordPop.
3625 *
3626 * @param records A list to add transactions to.
3627 * @param isRecordPop A list to add whether or not the transactions added to records is
3628 * a pop transaction.
3629 * @return true if something was added or false otherwise.
3630 */
3631 boolean generateOps(ArrayList<BackStackRecord> records, ArrayList<Boolean> isRecordPop);
3632 }
3633
3634 /**
3635 * A pop operation OpGenerator. This will be run on the UI thread and will generate the
3636 * transactions that will be popped if anything can be popped.
3637 */
3638 private class PopBackStackState implements OpGenerator {
3639 final String mName;
3640 final int mId;
3641 final int mFlags;
3642
3643 public PopBackStackState(String name, int id, int flags) {
3644 mName = name;
3645 mId = id;
3646 mFlags = flags;
3647 }
3648
3649 @Override
3650 public boolean generateOps(ArrayList<BackStackRecord> records,
3651 ArrayList<Boolean> isRecordPop) {
Adam Powell5f3a05c2017-01-27 16:51:03 -08003652 if (mPrimaryNav != null // We have a primary nav fragment
3653 && mId < 0 // No valid id (since they're local)
3654 && mName == null) { // no name to pop to (since they're local)
3655 final FragmentManager childManager = mPrimaryNav.mChildFragmentManager;
3656 if (childManager != null && childManager.popBackStackImmediate()) {
3657 // We didn't add any operations for this FragmentManager even though
3658 // a child did do work.
3659 return false;
3660 }
3661 }
George Mounteca8e222016-07-07 13:13:05 -07003662 return popBackStackState(records, isRecordPop, mName, mId, mFlags);
3663 }
3664 }
George Mount86bfc662016-07-12 16:06:06 -07003665
3666 /**
3667 * A listener for a postponed transaction. This waits until
3668 * {@link Fragment#startPostponedEnterTransition()} is called or a transaction is started
3669 * that interacts with this one, based on interactions with the fragment container.
3670 */
3671 static class StartEnterTransitionListener
3672 implements Fragment.OnStartEnterTransitionListener {
3673 private final boolean mIsBack;
3674 private final BackStackRecord mRecord;
3675 private int mNumPostponed;
3676
3677 public StartEnterTransitionListener(BackStackRecord record, boolean isBack) {
3678 mIsBack = isBack;
3679 mRecord = record;
3680 }
3681
3682 /**
3683 * Called from {@link Fragment#startPostponedEnterTransition()}, this decreases the
3684 * number of Fragments that are postponed. This may cause the transaction to schedule
3685 * to finish running and run transitions and animations.
3686 */
3687 @Override
3688 public void onStartEnterTransition() {
3689 mNumPostponed--;
3690 if (mNumPostponed != 0) {
3691 return;
3692 }
3693 mRecord.mManager.scheduleCommit();
3694 }
3695
3696 /**
3697 * Called from {@link Fragment#
3698 * setOnStartEnterTransitionListener(Fragment.OnStartEnterTransitionListener)}, this
3699 * increases the number of fragments that are postponed as part of this transaction.
3700 */
3701 @Override
3702 public void startListening() {
3703 mNumPostponed++;
3704 }
3705
3706 /**
3707 * @return true if there are no more postponed fragments as part of the transaction.
3708 */
3709 public boolean isReady() {
3710 return mNumPostponed == 0;
3711 }
3712
3713 /**
3714 * Completes the transaction and start the animations and transitions. This may skip
3715 * the transitions if this is called before all fragments have called
3716 * {@link Fragment#startPostponedEnterTransition()}.
3717 */
3718 public void completeTransaction() {
3719 final boolean canceled;
3720 canceled = mNumPostponed > 0;
3721 FragmentManagerImpl manager = mRecord.mManager;
3722 final int numAdded = manager.mAdded.size();
3723 for (int i = 0; i < numAdded; i++) {
3724 final Fragment fragment = manager.mAdded.get(i);
3725 fragment.setOnStartEnterTransitionListener(null);
3726 if (canceled && fragment.isPostponed()) {
3727 fragment.startPostponedEnterTransition();
3728 }
3729 }
3730 mRecord.mManager.completeExecute(mRecord, mIsBack, !canceled, true);
3731 }
3732
3733 /**
3734 * Cancels this transaction instead of completing it. That means that the state isn't
3735 * changed, so the pop results in no change to the state.
3736 */
3737 public void cancelTransaction() {
3738 mRecord.mManager.completeExecute(mRecord, mIsBack, false, false);
3739 }
3740 }
Dianne Hackborn2dedce62010-04-15 14:45:25 -07003741}