java.lang.Object

↳Activity

androidx.core.app.ComponentActivity

androidx.activity.ComponentActivity

↳androidx.fragment.app.FragmentActivity

Subclasses:

CarAppActivity, LauncherActivity, BaseCarAppActivity, AppSearchDebugActivity, SlicePermissionActivity, FragmentScenario.EmptyFragmentActivity, DeviceCredentialHandlerActivity, AppCompatActivity

Gradle dependencies

compile group: 'androidx.fragment', name: 'fragment', version: '1.8.3'

  • groupId: androidx.fragment
  • artifactId: fragment
  • version: 1.8.3

Artifact androidx.fragment:fragment:1.8.3 it located at Google repository (https://maven.google.com/)

Androidx artifact mapping:

androidx.fragment:fragment com.android.support:support-fragment

Androidx class mapping:

androidx.fragment.app.FragmentActivity android.support.v4.app.FragmentActivity

Overview

Base class for activities that want to use the support-based Fragments.

Known limitations:

  • When using the <fragment> tag, this implementation can not use the parent view's ID as the new fragment's ID. You must explicitly specify an ID (or tag) in the <fragment>.

Summary

Constructors
publicFragmentActivity()

Default constructor for FragmentActivity.

publicFragmentActivity(int contentLayoutId)

Alternate constructor that can be used to provide a default layout that will be inflated as part of super.onCreate(savedInstanceState).

Methods
public voiddump(java.lang.String prefix, java.io.FileDescriptor fd, java.io.PrintWriter writer, java.lang.String args[])

Print the Activity's state into the given stream.

public FragmentManagergetSupportFragmentManager()

Return the FragmentManager for interacting with fragments associated with this activity.

public LoaderManagergetSupportLoaderManager()

protected voidonActivityResult(int requestCode, int resultCode, Intent data)

public voidonAttachFragment(Fragment fragment)

Called when a fragment is attached to the activity.

protected voidonCreate(Bundle savedInstanceState)

Perform initialization of all fragments.

public ViewonCreateView(java.lang.String name, Context context, AttributeSet attrs)

public ViewonCreateView(View parent, java.lang.String name, Context context, AttributeSet attrs)

protected voidonDestroy()

Destroy all fragments.

public booleanonMenuItemSelected(int featureId, MenuItem item)

protected voidonPause()

Dispatch onPause() to fragments.

protected voidonPostResume()

Dispatch onResume() to fragments.

public voidonRequestPermissionsResult(int requestCode, java.lang.String permissions[], int[] grantResults[])

protected voidonResume()

Dispatch onResume() to fragments.

protected voidonResumeFragments()

This is the fragment-orientated version of FragmentActivity.onResume() that you can override to perform operations in the Activity at the same point where its fragments are resumed.

protected voidonStart()

Dispatch onStart() to all fragments.

public voidonStateNotSaved()

Hook in to note that fragment state is no longer saved.

protected voidonStop()

Dispatch onStop() to all fragments.

public voidsetEnterSharedElementCallback(SharedElementCallback callback)

When was used to start an Activity, callback will be called to handle shared elements on the launched Activity.

public voidsetExitSharedElementCallback(SharedElementCallback listener)

When was used to start an Activity, listener will be called to handle shared elements on the launching Activity.

public voidstartActivityFromFragment(Fragment fragment, Intent intent, int requestCode)

Called by Fragment.startActivityForResult() to implement its behavior.

public voidstartActivityFromFragment(Fragment fragment, Intent intent, int requestCode, Bundle options)

Called by Fragment.startActivityForResult() to implement its behavior.

public voidstartIntentSenderFromFragment(Fragment fragment, IntentSender intent, int requestCode, Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags, Bundle options)

Called by Fragment.startIntentSenderForResult() to implement its behavior.

public voidsupportFinishAfterTransition()

Reverses the Activity Scene entry Transition and triggers the calling Activity to reverse its exit Transition.

public voidsupportInvalidateOptionsMenu()

Support library version of .

public voidsupportPostponeEnterTransition()

Support library version of that works only on API 21 and later.

public voidsupportStartPostponedEnterTransition()

Support library version of that only works with API 21 and later.

public final voidvalidateRequestPermissionsRequestCode(int requestCode)

from ComponentActivityaddContentView, addMenuProvider, addMenuProvider, addMenuProvider, addOnConfigurationChangedListener, addOnContextAvailableListener, addOnMultiWindowModeChangedListener, addOnNewIntentListener, addOnPictureInPictureModeChangedListener, addOnTrimMemoryListener, getActivityResultRegistry, getDefaultViewModelCreationExtras, getDefaultViewModelProviderFactory, getLastCustomNonConfigurationInstance, getLifecycle, getOnBackPressedDispatcher, getSavedStateRegistry, getViewModelStore, invalidateMenu, onBackPressed, onConfigurationChanged, onCreateOptionsMenu, onMultiWindowModeChanged, onMultiWindowModeChanged, onNewIntent, onOptionsItemSelected, onPanelClosed, onPictureInPictureModeChanged, onPictureInPictureModeChanged, onPrepareOptionsMenu, onRetainCustomNonConfigurationInstance, onRetainNonConfigurationInstance, onSaveInstanceState, onTrimMemory, peekAvailableContext, registerForActivityResult, registerForActivityResult, removeMenuProvider, removeOnConfigurationChangedListener, removeOnContextAvailableListener, removeOnMultiWindowModeChangedListener, removeOnNewIntentListener, removeOnPictureInPictureModeChangedListener, removeOnTrimMemoryListener, reportFullyDrawn, setContentView, setContentView, setContentView, startActivityForResult, startActivityForResult, startIntentSenderForResult, startIntentSenderForResult
from ComponentActivitydispatchKeyEvent, dispatchKeyShortcutEvent, getExtraData, putExtraData, shouldDumpInternalState, superDispatchKeyEvent
from java.lang.Objectclone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait

Constructors

public FragmentActivity()

Default constructor for FragmentActivity. All Activities must have a default constructor for API 27 and lower devices or when using the default .

public FragmentActivity(int contentLayoutId)

Alternate constructor that can be used to provide a default layout that will be inflated as part of super.onCreate(savedInstanceState).

This should generally be called from your constructor that takes no parameters, as is required for API 27 and lower or when using the default .

See also: FragmentActivity.FragmentActivity()

Methods

protected void onActivityResult(int requestCode, int resultCode, Intent data)

Deprecated: This method has been deprecated in favor of using the Activity Result API which brings increased type safety via an ActivityResultContract and the prebuilt contracts for common intents available in ActivityResultContracts, provides hooks for testing, and allow receiving results in separate, testable classes independent from your activity. Use ComponentActivity.registerForActivityResult(ActivityResultContract, ActivityResultCallback) with the appropriate ActivityResultContract and handling the result in the callback.

public void supportFinishAfterTransition()

Reverses the Activity Scene entry Transition and triggers the calling Activity to reverse its exit Transition. When the exit Transition completes, FragmentActivity is called. If no entry Transition was used, finish() is called immediately and the Activity exit Transition is run.

On Android 4.4 or lower, this method only finishes the Activity with no special exit transition.

public void setEnterSharedElementCallback(SharedElementCallback callback)

When was used to start an Activity, callback will be called to handle shared elements on the launched Activity. This requires Window.

Parameters:

callback: Used to manipulate shared element transitions on the launched Activity.

public void setExitSharedElementCallback(SharedElementCallback listener)

When was used to start an Activity, listener will be called to handle shared elements on the launching Activity. Most calls will only come when returning from the started Activity. This requires Window.

Parameters:

listener: Used to manipulate shared element transitions on the launching Activity.

public void supportPostponeEnterTransition()

Support library version of that works only on API 21 and later.

public void supportStartPostponedEnterTransition()

Support library version of that only works with API 21 and later.

protected void onCreate(Bundle savedInstanceState)

Perform initialization of all fragments.

public View onCreateView(View parent, java.lang.String name, Context context, AttributeSet attrs)

public View onCreateView(java.lang.String name, Context context, AttributeSet attrs)

protected void onDestroy()

Destroy all fragments.

public boolean onMenuItemSelected(int featureId, MenuItem item)

protected void onPause()

Dispatch onPause() to fragments.

public void onStateNotSaved()

Hook in to note that fragment state is no longer saved.

protected void onResume()

Dispatch onResume() to fragments. Note that for better inter-operation with older versions of the platform, at the point of this call the fragments attached to the activity are not resumed.

protected void onPostResume()

Dispatch onResume() to fragments.

protected void onResumeFragments()

This is the fragment-orientated version of FragmentActivity.onResume() that you can override to perform operations in the Activity at the same point where its fragments are resumed. Be sure to always call through to the super-class.

protected void onStart()

Dispatch onStart() to all fragments.

protected void onStop()

Dispatch onStop() to all fragments.

public void supportInvalidateOptionsMenu()

Deprecated: Call directly.

Support library version of .

Invalidate the activity's options menu. This will cause relevant presentations of the menu to fully update via calls to onCreateOptionsMenu and onPrepareOptionsMenu the next time the menu is requested.

public void dump(java.lang.String prefix, java.io.FileDescriptor fd, java.io.PrintWriter writer, java.lang.String args[])

Print the Activity's state into the given stream. This gets invoked if you run "adb shell dumpsys activity ".

Parameters:

prefix: Desired prefix to prepend at each line of output.
fd: The raw file descriptor that the dump is being sent to.
writer: The PrintWriter to which you should dump your state. This will be closed for you after you return.
args: additional arguments to the dump request.

public void onAttachFragment(Fragment fragment)

Deprecated: The responsibility for listening for fragments being attached has been moved to FragmentManager. You can add a listener to this Activity's FragmentManager by calling FragmentManager.addFragmentOnAttachListener(FragmentOnAttachListener) in your constructor to get callbacks when a fragment is attached directly to the activity's FragmentManager.

Called when a fragment is attached to the activity.

This is called after the attached fragment's onAttach and before the attached fragment's onCreate if the fragment has not yet had a previous call to onCreate.

public FragmentManager getSupportFragmentManager()

Return the FragmentManager for interacting with fragments associated with this activity.

public LoaderManager getSupportLoaderManager()

Deprecated: Use LoaderManager.getInstance(this).

public final void validateRequestPermissionsRequestCode(int requestCode)

Deprecated: there are no longer any restrictions on permissions requestCodes.

public void onRequestPermissionsResult(int requestCode, java.lang.String permissions[], int[] grantResults[])

Deprecated: This method has been deprecated in favor of using the Activity Result API which brings increased type safety via an ActivityResultContract and the prebuilt contracts for common intents available in ActivityResultContracts, provides hooks for testing, and allow receiving results in separate, testable classes independent from your activity. Use ComponentActivity.registerForActivityResult(ActivityResultContract, ActivityResultCallback) passing in a ActivityResultContracts.RequestMultiplePermissions object for the ActivityResultContract and handling the result in the callback.

public void startActivityFromFragment(Fragment fragment, Intent intent, int requestCode)

Called by Fragment.startActivityForResult() to implement its behavior.

Parameters:

fragment: the Fragment to start the activity from.
intent: The intent to start.
requestCode: The request code to be returned in Fragment.onActivityResult(int, int, Intent) when the activity exits. Must be between 0 and 65535 to be considered valid. If given requestCode is greater than 65535, an IllegalArgumentException would be thrown.

public void startActivityFromFragment(Fragment fragment, Intent intent, int requestCode, Bundle options)

Called by Fragment.startActivityForResult() to implement its behavior.

Parameters:

fragment: the Fragment to start the activity from.
intent: The intent to start.
requestCode: The request code to be returned in Fragment.onActivityResult(int, int, Intent) when the activity exits. Must be between 0 and 65535 to be considered valid. If given requestCode is greater than 65535, an IllegalArgumentException would be thrown.
options: Additional options for how the Activity should be started. See for more details. This value may be null.

public void startIntentSenderFromFragment(Fragment fragment, IntentSender intent, int requestCode, Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags, Bundle options)

Deprecated: Fragments should use Fragment.registerForActivityResult(ActivityResultContract, ActivityResultCallback) with the ActivityResultContracts.StartIntentSenderForResult contract. This method will still be called when Fragments call the deprecated startIntentSenderForResult() method.

Called by Fragment.startIntentSenderForResult() to implement its behavior.

Parameters:

fragment: the Fragment to start the intent sender from.
intent: The IntentSender to launch.
requestCode: The request code to be returned in Fragment.onActivityResult(int, int, Intent) when the activity exits. Must be between 0 and 65535 to be considered valid. If given requestCode is greater than 65535, an IllegalArgumentException would be thrown.
fillInIntent: If non-null, this will be provided as the intent parameter to IntentSender. This value may be null.
flagsMask: Intent flags in the original IntentSender that you would like to change.
flagsValues: Desired values for any bits set in flagsMask.
extraFlags: Always set to 0.
options: Additional options for how the Activity should be started. See for more details. This value may be null.

Source

/*
 * Copyright 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package androidx.fragment.app;

import static androidx.activity.result.contract.ActivityResultContracts.StartIntentSenderForResult;

import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.IntentSender;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.Window;

import androidx.activity.ComponentActivity;
import androidx.activity.OnBackPressedDispatcher;
import androidx.activity.OnBackPressedDispatcherOwner;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultRegistry;
import androidx.activity.result.ActivityResultRegistryOwner;
import androidx.activity.result.contract.ActivityResultContract;
import androidx.annotation.CallSuper;
import androidx.annotation.ContentView;
import androidx.annotation.LayoutRes;
import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.core.app.MultiWindowModeChangedInfo;
import androidx.core.app.OnMultiWindowModeChangedProvider;
import androidx.core.app.OnPictureInPictureModeChangedProvider;
import androidx.core.app.PictureInPictureModeChangedInfo;
import androidx.core.app.SharedElementCallback;
import androidx.core.content.OnConfigurationChangedProvider;
import androidx.core.content.OnTrimMemoryProvider;
import androidx.core.util.Consumer;
import androidx.core.view.MenuHost;
import androidx.core.view.MenuProvider;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.LifecycleRegistry;
import androidx.lifecycle.ViewModelStore;
import androidx.lifecycle.ViewModelStoreOwner;
import androidx.loader.app.LoaderManager;
import androidx.savedstate.SavedStateRegistry;
import androidx.savedstate.SavedStateRegistryOwner;

import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Collection;

/**
 * Base class for activities that want to use the support-based
 * {@link Fragment Fragments}.
 *
 * <p>Known limitations:</p>
 * <ul>
 * <li> <p>When using the <code>&lt;fragment></code> tag, this implementation can not
 * use the parent view's ID as the new fragment's ID.  You must explicitly
 * specify an ID (or tag) in the <code>&lt;fragment></code>.</p>
 * </ul>
 */
public class FragmentActivity extends ComponentActivity implements
        ActivityCompat.OnRequestPermissionsResultCallback,
        ActivityCompat.RequestPermissionsRequestCodeValidator {

    static final String LIFECYCLE_TAG = "android:support:lifecycle";

    final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
    /**
     * A {@link Lifecycle} that is exactly nested outside of when the FragmentController
     * has its state changed, providing the proper nesting of Lifecycle callbacks
     * <p>
     * TODO(b/127528777) Drive Fragment Lifecycle with LifecycleObserver
     */
    final LifecycleRegistry mFragmentLifecycleRegistry = new LifecycleRegistry(this);

    boolean mCreated;
    boolean mResumed;
    boolean mStopped = true;

    /**
     * Default constructor for FragmentActivity. All Activities must have a default constructor
     * for API 27 and lower devices or when using the default
     * {@link android.app.AppComponentFactory}.
     */
    public FragmentActivity() {
        super();
        init();
    }

    /**
     * Alternate constructor that can be used to provide a default layout
     * that will be inflated as part of <code>super.onCreate(savedInstanceState)</code>.
     *
     * <p>This should generally be called from your constructor that takes no parameters,
     * as is required for API 27 and lower or when using the default
     * {@link android.app.AppComponentFactory}.
     *
     * @see #FragmentActivity()
     */
    @ContentView
    public FragmentActivity(@LayoutRes int contentLayoutId) {
        super(contentLayoutId);
        init();
    }

    private void init() {
        getSavedStateRegistry().registerSavedStateProvider(LIFECYCLE_TAG, () -> {
            markFragmentsCreated();
            mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
            return new Bundle();
        });
        // Ensure that the first OnConfigurationChangedListener
        // marks the FragmentManager's state as not saved
        addOnConfigurationChangedListener(newConfig -> mFragments.noteStateNotSaved());
        // Ensure that the first OnNewIntentListener
        // marks the FragmentManager's state as not saved
        addOnNewIntentListener(newConfig -> mFragments.noteStateNotSaved());
        addOnContextAvailableListener(context -> mFragments.attachHost(null /*parent*/));
    }

    // ------------------------------------------------------------------------
    // HOOKS INTO ACTIVITY
    // ------------------------------------------------------------------------

    @SuppressWarnings("deprecation")
    @Override
    @CallSuper
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        mFragments.noteStateNotSaved();
        super.onActivityResult(requestCode, resultCode, data);
    }


    /**
     * Reverses the Activity Scene entry Transition and triggers the calling Activity
     * to reverse its exit Transition. When the exit Transition completes,
     * {@link #finish()} is called. If no entry Transition was used, finish() is called
     * immediately and the Activity exit Transition is run.
     *
     * <p>On Android 4.4 or lower, this method only finishes the Activity with no
     * special exit transition.</p>
     */
    public void supportFinishAfterTransition() {
        ActivityCompat.finishAfterTransition(this);
    }

    /**
     * When {@link android.app.ActivityOptions#makeSceneTransitionAnimation(Activity,
     * android.view.View, String)} was used to start an Activity, <var>callback</var>
     * will be called to handle shared elements on the <i>launched</i> Activity. This requires
     * {@link Window#FEATURE_CONTENT_TRANSITIONS}.
     *
     * @param callback Used to manipulate shared element transitions on the launched Activity.
     */
    public void setEnterSharedElementCallback(@Nullable SharedElementCallback callback) {
        ActivityCompat.setEnterSharedElementCallback(this, callback);
    }

    /**
     * When {@link android.app.ActivityOptions#makeSceneTransitionAnimation(Activity,
     * android.view.View, String)} was used to start an Activity, <var>listener</var>
     * will be called to handle shared elements on the <i>launching</i> Activity. Most
     * calls will only come when returning from the started Activity.
     * This requires {@link Window#FEATURE_CONTENT_TRANSITIONS}.
     *
     * @param listener Used to manipulate shared element transitions on the launching Activity.
     */
    public void setExitSharedElementCallback(@Nullable SharedElementCallback listener) {
        ActivityCompat.setExitSharedElementCallback(this, listener);
    }

    /**
     * Support library version of {@link android.app.Activity#postponeEnterTransition()} that works
     * only on API 21 and later.
     */
    public void supportPostponeEnterTransition() {
        ActivityCompat.postponeEnterTransition(this);
    }

    /**
     * Support library version of {@link android.app.Activity#startPostponedEnterTransition()}
     * that only works with API 21 and later.
     */
    public void supportStartPostponedEnterTransition() {
        ActivityCompat.startPostponedEnterTransition(this);
    }

    /**
     * {@inheritDoc}
     *
     * Perform initialization of all fragments.
     */
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
        mFragments.dispatchCreate();
    }

    @Override
    @Nullable
    public View onCreateView(@Nullable View parent, @NonNull String name, @NonNull Context context,
            @NonNull AttributeSet attrs) {
        final View v = dispatchFragmentsOnCreateView(parent, name, context, attrs);
        if (v == null) {
            return super.onCreateView(parent, name, context, attrs);
        }
        return v;
    }

    @Override
    @Nullable
    public View onCreateView(@NonNull String name, @NonNull Context context,
            @NonNull AttributeSet attrs) {
        final View v = dispatchFragmentsOnCreateView(null, name, context, attrs);
        if (v == null) {
            return super.onCreateView(name, context, attrs);
        }
        return v;
    }

    @Nullable
    final View dispatchFragmentsOnCreateView(@Nullable View parent, @NonNull String name,
            @NonNull Context context, @NonNull AttributeSet attrs) {
        return mFragments.onCreateView(parent, name, context, attrs);
    }

    /**
     * {@inheritDoc}
     *
     * Destroy all fragments.
     */
    @Override
    protected void onDestroy() {
        super.onDestroy();
        mFragments.dispatchDestroy();
        mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
    }

    @Override
    public boolean onMenuItemSelected(int featureId, @NonNull MenuItem item) {
        if (super.onMenuItemSelected(featureId, item)) {
            return true;
        }

        if (featureId == Window.FEATURE_CONTEXT_MENU) {
            return mFragments.dispatchContextItemSelected(item);
        }

        return false;
    }

    /**
     * {@inheritDoc}
     *
     * Dispatch onPause() to fragments.
     */
    @Override
    protected void onPause() {
        super.onPause();
        mResumed = false;
        mFragments.dispatchPause();
        mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE);
    }

    /**
     * {@inheritDoc}
     *
     * Hook in to note that fragment state is no longer saved.
     */
    @SuppressWarnings("deprecation")
    @Override
    public void onStateNotSaved() {
        mFragments.noteStateNotSaved();
    }

    /**
     * {@inheritDoc}
     *
     * Dispatch onResume() to fragments.  Note that for better inter-operation
     * with older versions of the platform, at the point of this call the
     * fragments attached to the activity are <em>not</em> resumed.
     */
    @Override
    protected void onResume() {
        mFragments.noteStateNotSaved();
        super.onResume();
        mResumed = true;
        mFragments.execPendingActions();
    }

    /**
     * {@inheritDoc}
     *
     * Dispatch onResume() to fragments.
     */
    @Override
    protected void onPostResume() {
        super.onPostResume();
        onResumeFragments();
    }

    /**
     * This is the fragment-orientated version of {@link #onResume()} that you
     * can override to perform operations in the Activity at the same point
     * where its fragments are resumed.  Be sure to always call through to
     * the super-class.
     */
    protected void onResumeFragments() {
        mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
        mFragments.dispatchResume();
    }

    /**
     * {@inheritDoc}
     *
     * Dispatch onStart() to all fragments.
     */
    @Override
    protected void onStart() {
        mFragments.noteStateNotSaved();
        super.onStart();

        mStopped = false;

        if (!mCreated) {
            mCreated = true;
            mFragments.dispatchActivityCreated();
        }

        mFragments.execPendingActions();

        // NOTE: HC onStart goes here.

        mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_START);
        mFragments.dispatchStart();
    }

    /**
     * {@inheritDoc}
     *
     * Dispatch onStop() to all fragments.
     */
    @Override
    protected void onStop() {
        super.onStop();

        mStopped = true;
        markFragmentsCreated();

        mFragments.dispatchStop();
        mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
    }

    // ------------------------------------------------------------------------
    // NEW METHODS
    // ------------------------------------------------------------------------

    /**
     * Support library version of {@link Activity#invalidateOptionsMenu}.
     *
     * <p>Invalidate the activity's options menu. This will cause relevant presentations
     * of the menu to fully update via calls to onCreateOptionsMenu and
     * onPrepareOptionsMenu the next time the menu is requested.
     *
     * @deprecated Call {@link Activity#invalidateOptionsMenu} directly.
     */
    @SuppressWarnings("DeprecatedIsStillUsed")
    @Deprecated
    public void supportInvalidateOptionsMenu() {
        invalidateMenu();
    }

    /**
     * Print the Activity's state into the given stream.  This gets invoked if
     * you run "adb shell dumpsys activity <activity_component_name>".
     *
     * @param prefix Desired prefix to prepend at each line of output.
     * @param fd The raw file descriptor that the dump is being sent to.
     * @param writer The PrintWriter to which you should dump your state.  This will be
     * closed for you after you return.
     * @param args additional arguments to the dump request.
     */
    @SuppressWarnings("deprecation")
    @Override
    public void dump(@NonNull String prefix, @Nullable FileDescriptor fd,
            @NonNull PrintWriter writer, @Nullable String[] args) {
        super.dump(prefix, fd, writer, args);

        if (!shouldDumpInternalState(args)) {
            return;
        }

        writer.print(prefix); writer.print("Local FragmentActivity ");
                writer.print(Integer.toHexString(System.identityHashCode(this)));
                writer.println(" State:");
        String innerPrefix = prefix + "  ";
        writer.print(innerPrefix); writer.print("mCreated=");
                writer.print(mCreated); writer.print(" mResumed=");
                writer.print(mResumed); writer.print(" mStopped=");
                writer.print(mStopped);

        if (getApplication() != null) {
            LoaderManager.getInstance(this).dump(innerPrefix, fd, writer, args);
        }
        mFragments.getSupportFragmentManager().dump(prefix, fd, writer, args);
    }

    // ------------------------------------------------------------------------
    // FRAGMENT SUPPORT
    // ------------------------------------------------------------------------

    /**
     * Called when a fragment is attached to the activity.
     *
     * <p>This is called after the attached fragment's <code>onAttach</code> and before
     * the attached fragment's <code>onCreate</code> if the fragment has not yet had a previous
     * call to <code>onCreate</code>.</p>
     *
     * @deprecated The responsibility for listening for fragments being attached has been moved
     * to FragmentManager. You can add a listener to
     * {@link #getSupportFragmentManager() this Activity's FragmentManager} by calling
     * {@link FragmentManager#addFragmentOnAttachListener(FragmentOnAttachListener)}
     * in your constructor to get callbacks when a fragment is attached directly to
     * the activity's FragmentManager.
     */
    @SuppressWarnings({"unused", "DeprecatedIsStillUsed"})
    @Deprecated
    @MainThread
    public void onAttachFragment(@NonNull Fragment fragment) {
    }

    /**
     * Return the FragmentManager for interacting with fragments associated
     * with this activity.
     */
    @NonNull
    public FragmentManager getSupportFragmentManager() {
        return mFragments.getSupportFragmentManager();
    }

    /**
     * @deprecated Use
     * {@link LoaderManager#getInstance(LifecycleOwner) LoaderManager.getInstance(this)}.
     */
    @Deprecated
    @NonNull
    public LoaderManager getSupportLoaderManager() {
        return LoaderManager.getInstance(this);
    }

    /**
     * {@inheritDoc}
     *
     * @deprecated there are no longer any restrictions on permissions requestCodes.
     */
    @Override
    @Deprecated
    public final void validateRequestPermissionsRequestCode(int requestCode) { }

    @SuppressWarnings("deprecation")
    @CallSuper
    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
            @NonNull int[] grantResults) {
        mFragments.noteStateNotSaved();
        super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    }

    /**
     * Called by Fragment.startActivityForResult() to implement its behavior.
     *
     * @param fragment the Fragment to start the activity from.
     * @param intent The intent to start.
     * @param requestCode The request code to be returned in
     * {@link Fragment#onActivityResult(int, int, Intent)} when the activity exits. Must be
     *                    between 0 and 65535 to be considered valid. If given requestCode is
     *                    greater than 65535, an IllegalArgumentException would be thrown.
     */
    public void startActivityFromFragment(@NonNull Fragment fragment,
            @NonNull Intent intent, int requestCode) {
        startActivityFromFragment(fragment, intent, requestCode, null);
    }

    /**
     * Called by Fragment.startActivityForResult() to implement its behavior.
     *
     * @param fragment the Fragment to start the activity from.
     * @param intent The intent to start.
     * @param requestCode The request code to be returned in
     * {@link Fragment#onActivityResult(int, int, Intent)} when the activity exits. Must be
     *                    between 0 and 65535 to be considered valid. If given requestCode is
     *                    greater than 65535, an IllegalArgumentException would be thrown.
     * @param options Additional options for how the Activity should be started. See
     * {@link Context#startActivity(Intent, Bundle)} for more details. This value may be null.
     */
    @SuppressWarnings("deprecation")
    public void startActivityFromFragment(@NonNull Fragment fragment,
            @NonNull Intent intent, int requestCode,
            @Nullable Bundle options) {
        // request code will be -1 if called from fragment.startActivity
        if (requestCode == -1) {
            ActivityCompat.startActivityForResult(this, intent, -1, options);
            return;
        }
        // If for some reason this method is being called directly with a requestCode that is not
        // -1, redirect it to the fragment.startActivityForResult method
        fragment.startActivityForResult(intent, requestCode, options);
    }

    /**
     * Called by Fragment.startIntentSenderForResult() to implement its behavior.
     *
     * @param fragment the Fragment to start the intent sender from.
     * @param intent The IntentSender to launch.
     * @param requestCode The request code to be returned in
     * {@link Fragment#onActivityResult(int, int, Intent)} when the activity exits. Must be
     *                    between 0 and 65535 to be considered valid. If given requestCode is
     *                    greater than 65535, an IllegalArgumentException would be thrown.
     * @param fillInIntent If non-null, this will be provided as the intent parameter to
     * {@link IntentSender#sendIntent(Context, int, Intent, IntentSender.OnFinished, Handler)}.
     *                     This value may be null.
     * @param flagsMask Intent flags in the original IntentSender that you would like to change.
     * @param flagsValues Desired values for any bits set in <code>flagsMask</code>.
     * @param extraFlags Always set to 0.
     * @param options Additional options for how the Activity should be started. See
     * {@link Context#startActivity(Intent, Bundle)} for more details. This value may be null.
     * @throws IntentSender.SendIntentException if the call fails to execute.
     *
     * @deprecated Fragments should use
     * {@link Fragment#registerForActivityResult(ActivityResultContract, ActivityResultCallback)}
     * with the {@link StartIntentSenderForResult} contract. This method will still be called when
     * Fragments call the deprecated <code>startIntentSenderForResult()</code> method.
     */
    @SuppressWarnings({"deprecation"})
    @Deprecated
    public void startIntentSenderFromFragment(@NonNull Fragment fragment,
            @NonNull IntentSender intent, int requestCode,
            @Nullable Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags,
            @Nullable Bundle options) throws IntentSender.SendIntentException {
        if (requestCode == -1) {
            ActivityCompat.startIntentSenderForResult(this, intent, requestCode, fillInIntent,
                    flagsMask, flagsValues, extraFlags, options);
            return;
        }
        fragment.startIntentSenderForResult(intent, requestCode, fillInIntent, flagsMask,
                flagsValues, extraFlags, options);
    }

    class HostCallbacks extends FragmentHostCallback<FragmentActivity> implements
            OnConfigurationChangedProvider,
            OnTrimMemoryProvider,
            OnMultiWindowModeChangedProvider,
            OnPictureInPictureModeChangedProvider,
            ViewModelStoreOwner,
            OnBackPressedDispatcherOwner,
            ActivityResultRegistryOwner,
            SavedStateRegistryOwner,
            FragmentOnAttachListener,
            MenuHost {

        public HostCallbacks() {
            super(FragmentActivity.this /*fragmentActivity*/);
        }

        @NonNull
        @Override
        public Lifecycle getLifecycle() {
            // Instead of directly using the Activity's Lifecycle, we
            // use a LifecycleRegistry that is nested exactly outside of
            // when Fragments get their lifecycle changed
            // TODO(b/127528777) Drive Fragment Lifecycle with LifecycleObserver
            return mFragmentLifecycleRegistry;
        }

        @NonNull
        @Override
        public ViewModelStore getViewModelStore() {
            return FragmentActivity.this.getViewModelStore();
        }

        @NonNull
        @Override
        public OnBackPressedDispatcher getOnBackPressedDispatcher() {
            return FragmentActivity.this.getOnBackPressedDispatcher();
        }

        @Override
        public void onDump(@NonNull String prefix, @Nullable FileDescriptor fd,
                @NonNull PrintWriter writer, @Nullable String[] args) {
            FragmentActivity.this.dump(prefix, fd, writer, args);
        }

        @Override
        public boolean onShouldSaveFragmentState(@NonNull Fragment fragment) {
            return !isFinishing();
        }

        @Override
        @NonNull
        public LayoutInflater onGetLayoutInflater() {
            return FragmentActivity.this.getLayoutInflater().cloneInContext(FragmentActivity.this);
        }

        @Override
        public FragmentActivity onGetHost() {
            return FragmentActivity.this;
        }

        @Override
        public void onSupportInvalidateOptionsMenu() {
            invalidateMenu();
        }

        @Override
        public boolean onShouldShowRequestPermissionRationale(@NonNull String permission) {
            return ActivityCompat.shouldShowRequestPermissionRationale(
                    FragmentActivity.this, permission);
        }

        @Override
        public boolean onHasWindowAnimations() {
            return getWindow() != null;
        }

        @Override
        public int onGetWindowAnimations() {
            final Window w = getWindow();
            return (w == null) ? 0 : w.getAttributes().windowAnimations;
        }

        @SuppressWarnings("deprecation")
        @Override
        public void onAttachFragment(@NonNull FragmentManager fragmentManager,
                @NonNull Fragment fragment) {
            FragmentActivity.this.onAttachFragment(fragment);
        }

        @Nullable
        @Override
        public View onFindViewById(int id) {
            return FragmentActivity.this.findViewById(id);
        }

        @Override
        public boolean onHasView() {
            final Window w = getWindow();
            return (w != null && w.peekDecorView() != null);
        }

        @NonNull
        @Override
        public ActivityResultRegistry getActivityResultRegistry() {
            return FragmentActivity.this.getActivityResultRegistry();
        }

        @NonNull
        @Override
        public SavedStateRegistry getSavedStateRegistry() {
            return FragmentActivity.this.getSavedStateRegistry();
        }

        @Override
        public void addOnConfigurationChangedListener(
                @NonNull Consumer<Configuration> listener
        ) {
            FragmentActivity.this.addOnConfigurationChangedListener(listener);
        }

        @Override
        public void removeOnConfigurationChangedListener(
                @NonNull Consumer<Configuration> listener
        ) {
            FragmentActivity.this.removeOnConfigurationChangedListener(listener);
        }

        @Override
        public void addOnTrimMemoryListener(@NonNull Consumer<Integer> listener) {
            FragmentActivity.this.addOnTrimMemoryListener(listener);
        }

        @Override
        public void removeOnTrimMemoryListener(@NonNull Consumer<Integer> listener) {
            FragmentActivity.this.removeOnTrimMemoryListener(listener);
        }

        @Override
        public void addOnMultiWindowModeChangedListener(
                @NonNull Consumer<MultiWindowModeChangedInfo> listener) {
            FragmentActivity.this.addOnMultiWindowModeChangedListener(listener);
        }

        @Override
        public void removeOnMultiWindowModeChangedListener(
                @NonNull Consumer<MultiWindowModeChangedInfo> listener) {
            FragmentActivity.this.removeOnMultiWindowModeChangedListener(listener);
        }

        @Override
        public void addOnPictureInPictureModeChangedListener(
                @NonNull Consumer<PictureInPictureModeChangedInfo> listener) {
            FragmentActivity.this.addOnPictureInPictureModeChangedListener(listener);
        }

        @Override
        public void removeOnPictureInPictureModeChangedListener(
                @NonNull Consumer<PictureInPictureModeChangedInfo> listener) {
            FragmentActivity.this.removeOnPictureInPictureModeChangedListener(listener);
        }

        @Override
        public void addMenuProvider(@NonNull MenuProvider provider) {
            FragmentActivity.this.addMenuProvider(provider);
        }

        @Override
        public void addMenuProvider(@NonNull MenuProvider provider, @NonNull LifecycleOwner owner) {
            FragmentActivity.this.addMenuProvider(provider, owner);
        }

        @Override
        public void addMenuProvider(@NonNull MenuProvider provider, @NonNull LifecycleOwner owner,
                @NonNull Lifecycle.State state) {
            FragmentActivity.this.addMenuProvider(provider, owner, state);
        }

        @Override
        public void removeMenuProvider(@NonNull MenuProvider provider) {
            FragmentActivity.this.removeMenuProvider(provider);
        }

        @Override
        public void invalidateMenu() {
            FragmentActivity.this.invalidateMenu();
        }
    }

    void markFragmentsCreated() {
        boolean reiterate;
        do {
            reiterate = markState(getSupportFragmentManager(), Lifecycle.State.CREATED);
        } while (reiterate);
    }

    private static boolean markState(FragmentManager manager, Lifecycle.State state) {
        boolean hadNotMarked = false;
        Collection<Fragment> fragments = manager.getFragments();
        for (Fragment fragment : fragments) {
            if (fragment == null) {
                continue;
            }
            if (fragment.getHost() != null) {
                FragmentManager childFragmentManager = fragment.getChildFragmentManager();
                hadNotMarked |= markState(childFragmentManager, state);
            }
            if (fragment.mViewLifecycleOwner != null && fragment.mViewLifecycleOwner
                    .getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
                fragment.mViewLifecycleOwner.setCurrentState(state);
                hadNotMarked = true;
            }
            if (fragment.mLifecycleRegistry.getCurrentState().isAtLeast(Lifecycle.State.STARTED)) {
                fragment.mLifecycleRegistry.setCurrentState(state);
                hadNotMarked = true;
            }
        }
        return hadNotMarked;
    }
}