Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 62bea2f1 authored by Dianne Hackborn's avatar Dianne Hackborn
Browse files

Nested fragments.

Change-Id: I79acc19b391352c16b06afee2ca543223c38e364
parent 18e87680
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -3348,6 +3348,7 @@ package android.app {
    method public final boolean equals(java.lang.Object);
    method public final android.app.Activity getActivity();
    method public final android.os.Bundle getArguments();
    method public final android.app.FragmentManager getChildFragmentManager();
    method public final android.app.FragmentManager getFragmentManager();
    method public final int getId();
    method public android.app.LoaderManager getLoaderManager();
@@ -3399,6 +3400,7 @@ package android.app {
    method public void onStop();
    method public void onTrimMemory(int);
    method public void onViewCreated(android.view.View, android.os.Bundle);
    method public void onViewStateRestored(android.os.Bundle);
    method public void registerForContextMenu(android.view.View);
    method public void setArguments(android.os.Bundle);
    method public void setHasOptionsMenu(boolean);
+45 −25
Original line number Diff line number Diff line
@@ -653,8 +653,9 @@ public class Activity extends ContextThemeWrapper
    /** Start of user-defined activity results. */
    public static final int RESULT_FIRST_USER   = 1;

    static final String FRAGMENTS_TAG = "android:fragments";

    private static final String WINDOW_HIERARCHY_TAG = "android:viewHierarchyState";
    private static final String FRAGMENTS_TAG = "android:fragments";
    private static final String SAVED_DIALOG_IDS_KEY = "android:savedDialogIds";
    private static final String SAVED_DIALOGS_TAG = "android:savedDialogs";
    private static final String SAVED_DIALOG_KEY_PREFIX = "android:dialog_";
@@ -697,7 +698,7 @@ public class Activity extends ContextThemeWrapper
        Object activity;
        HashMap<String, Object> children;
        ArrayList<Fragment> fragments;
        SparseArray<LoaderManagerImpl> loaders;
        HashMap<String, LoaderManagerImpl> loaders;
    }
    /* package */ NonConfigurationInstances mLastNonConfigurationInstances;
    
@@ -715,8 +716,14 @@ public class Activity extends ContextThemeWrapper
    private int mTitleColor = 0;

    final FragmentManagerImpl mFragments = new FragmentManagerImpl();
    final FragmentContainer mContainer = new FragmentContainer() {
        @Override
        public View findViewById(int id) {
            return Activity.this.findViewById(id);
        }
    };
    
    SparseArray<LoaderManagerImpl> mAllLoaderManagers;
    HashMap<String, LoaderManagerImpl> mAllLoaderManagers;
    LoaderManagerImpl mLoaderManager;
    
    private static final class ManagedCursor {
@@ -744,6 +751,7 @@ public class Activity extends ContextThemeWrapper
    
    protected static final int[] FOCUSED_STATE_SET = {com.android.internal.R.attr.state_focused};

    @SuppressWarnings("unused")
    private final Object mInstanceTracker = StrictMode.trackActivity(this);

    private Thread mUiThread;
@@ -808,19 +816,19 @@ public class Activity extends ContextThemeWrapper
            return mLoaderManager;
        }
        mCheckedForLoaderManager = true;
        mLoaderManager = getLoaderManager(-1, mLoadersStarted, true);
        mLoaderManager = getLoaderManager(null, mLoadersStarted, true);
        return mLoaderManager;
    }
    
    LoaderManagerImpl getLoaderManager(int index, boolean started, boolean create) {
    LoaderManagerImpl getLoaderManager(String who, boolean started, boolean create) {
        if (mAllLoaderManagers == null) {
            mAllLoaderManagers = new SparseArray<LoaderManagerImpl>();
            mAllLoaderManagers = new HashMap<String, LoaderManagerImpl>();
        }
        LoaderManagerImpl lm = mAllLoaderManagers.get(index);
        LoaderManagerImpl lm = mAllLoaderManagers.get(who);
        if (lm == null) {
            if (create) {
                lm = new LoaderManagerImpl(this, started);
                mAllLoaderManagers.put(index, lm);
                lm = new LoaderManagerImpl(who, this, started);
                mAllLoaderManagers.put(who, lm);
            }
        } else {
            lm.updateActivity(this);
@@ -1025,7 +1033,7 @@ public class Activity extends ContextThemeWrapper
            if (mLoaderManager != null) {
                mLoaderManager.doStart();
            } else if (!mCheckedForLoaderManager) {
                mLoaderManager = getLoaderManager(-1, mLoadersStarted, false);
                mLoaderManager = getLoaderManager(null, mLoadersStarted, false);
            }
            mCheckedForLoaderManager = true;
        }
@@ -1601,13 +1609,17 @@ public class Activity extends ContextThemeWrapper
        if (mAllLoaderManagers != null) {
            // prune out any loader managers that were already stopped and so
            // have nothing useful to retain.
            for (int i=mAllLoaderManagers.size()-1; i>=0; i--) {
                LoaderManagerImpl lm = mAllLoaderManagers.valueAt(i);
            LoaderManagerImpl loaders[] = new LoaderManagerImpl[mAllLoaderManagers.size()];
            mAllLoaderManagers.values().toArray(loaders);
            if (loaders != null) {
                for (int i=0; i<loaders.length; i++) {
                    LoaderManagerImpl lm = loaders[i];
                    if (lm.mRetaining) {
                        retainLoaders = true;
                    } else {
                        lm.doDestroy();
                    mAllLoaderManagers.removeAt(i);
                        mAllLoaderManagers.remove(lm.mWho);
                    }
                }
            }
        }
@@ -1643,13 +1655,13 @@ public class Activity extends ContextThemeWrapper
        return mFragments;
    }

    void invalidateFragmentIndex(int index) {
    void invalidateFragment(String who) {
        //Log.v(TAG, "invalidateFragmentIndex: index=" + index);
        if (mAllLoaderManagers != null) {
            LoaderManagerImpl lm = mAllLoaderManagers.get(index);
            LoaderManagerImpl lm = mAllLoaderManagers.get(who);
            if (lm != null && !lm.mRetaining) {
                lm.doDestroy();
                mAllLoaderManagers.remove(index);
                mAllLoaderManagers.remove(who);
            }
        }
    }
@@ -4739,6 +4751,10 @@ public class Activity extends ContextThemeWrapper
     * @param args additional arguments to the dump request.
     */
    public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
        dumpInner(prefix, fd, writer, args);
    }

    void dumpInner(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
        writer.print(prefix); writer.print("Local Activity ");
                writer.print(Integer.toHexString(System.identityHashCode(this)));
                writer.println(" State:");
@@ -5019,7 +5035,7 @@ public class Activity extends ContextThemeWrapper
            Configuration config) {
        attachBaseContext(context);

        mFragments.attachActivity(this);
        mFragments.attachActivity(this, mContainer, null);
        
        mWindow = PolicyManager.makeNewWindow(this);
        mWindow.setCallback(this);
@@ -5080,13 +5096,17 @@ public class Activity extends ContextThemeWrapper
        }
        mFragments.dispatchStart();
        if (mAllLoaderManagers != null) {
            for (int i=mAllLoaderManagers.size()-1; i>=0; i--) {
                LoaderManagerImpl lm = mAllLoaderManagers.valueAt(i);
            LoaderManagerImpl loaders[] = new LoaderManagerImpl[mAllLoaderManagers.size()];
            mAllLoaderManagers.values().toArray(loaders);
            if (loaders != null) {
                for (int i=0; i<loaders.length; i++) {
                    LoaderManagerImpl lm = loaders[i];
                    lm.finishRetain();
                    lm.doReportStart();
                }
            }
        }
    }
    
    final void performRestart() {
        mFragments.noteStateNotSaved();
+306 −12
Original line number Diff line number Diff line
@@ -85,7 +85,7 @@ final class FragmentState implements Parcelable {
        mSavedFragmentState = in.readBundle();
    }
    
    public Fragment instantiate(Activity activity) {
    public Fragment instantiate(Activity activity, Fragment parent) {
        if (mInstance != null) {
            return mInstance;
        }
@@ -100,7 +100,7 @@ final class FragmentState implements Parcelable {
            mSavedFragmentState.setClassLoader(activity.getClassLoader());
            mInstance.mSavedFragmentState = mSavedFragmentState;
        }
        mInstance.setIndex(mIndex);
        mInstance.setIndex(mIndex, parent);
        mInstance.mFromLayout = mFromLayout;
        mInstance.mRestored = true;
        mInstance.mFragmentId = mFragmentId;
@@ -207,6 +207,8 @@ final class FragmentState implements Parcelable {
 * with the fragment.
 * <li> {@link #onActivityCreated} tells the fragment that its activity has
 * completed its own {@link Activity#onCreate Activity.onCreate()}.
 * <li> {@link #onViewStateRestored} tells the fragment that all of the saved
 * state of its view hierarchy has been restored.
 * <li> {@link #onStart} makes the fragment visible to the user (based on its
 * containing activity being started).
 * <li> {@link #onResume} makes the fragment interacting with the user (based on its
@@ -413,6 +415,12 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
    // Activity this fragment is attached to.
    Activity mActivity;

    // Private fragment manager for child fragments inside of this one.
    FragmentManagerImpl mChildFragmentManager;

    // If this Fragment is contained in another Fragment, this is that container.
    Fragment mParentFragment;

    // The optional identifier for this fragment -- either the container ID if it
    // was dynamically added to the view hierarchy, or the ID supplied in
    // layout.
@@ -595,17 +603,27 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
        }
    }
    
    final void restoreViewState() {
    final void restoreViewState(Bundle savedInstanceState) {
        if (mSavedViewState != null) {
            mView.restoreHierarchyState(mSavedViewState);
            mSavedViewState = null;
        }
        mCalled = false;
        onViewStateRestored(savedInstanceState);
        if (!mCalled) {
            throw new SuperNotCalledException("Fragment " + this
                    + " did not call through to super.onViewStateRestored()");
        }
    }
    
    final void setIndex(int index) {
    final void setIndex(int index, Fragment parent) {
        mIndex = index;
        if (parent != null) {
            mWho = parent.mWho + ":" + mIndex;
        } else {
            mWho = "android:fragment:" + mIndex;
        }
   }
    
    final boolean isInBackStack() {
        return mBackStackNesting > 0;
@@ -785,11 +803,34 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
     * before {@link #getActivity()}, during the time from when the fragment is
     * placed in a {@link FragmentTransaction} until it is committed and
     * attached to its activity.
     *
     * <p>If this Fragment is a child of another Fragment, the FragmentManager
     * returned here will be the parent's {@link #getChildFragmentManager()}.
     */
    final public FragmentManager getFragmentManager() {
        return mFragmentManager;
    }

    /**
     * Return a private FragmentManager for placing and managing Fragments
     * inside of this Fragment.
     */
    final public FragmentManager getChildFragmentManager() {
        if (mChildFragmentManager == null) {
            instantiateChildFragmentManager();
            if (mState >= RESUMED) {
                mChildFragmentManager.dispatchResume();
            } else if (mState >= STARTED) {
                mChildFragmentManager.dispatchStart();
            } else if (mState >= ACTIVITY_CREATED) {
                mChildFragmentManager.dispatchActivityCreated();
            } else if (mState >= CREATED) {
                mChildFragmentManager.dispatchCreate();
            }
        }
        return mChildFragmentManager;
    }

    /**
     * Return true if the fragment is currently added to its activity.
     */
@@ -880,6 +921,10 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
     * </ul>
     */
    public void setRetainInstance(boolean retain) {
        if (retain && mParentFragment != null) {
            throw new IllegalStateException(
                    "Can't retain fragements that are nested in other fragments");
        }
        mRetainInstance = retain;
    }
    
@@ -961,7 +1006,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
            throw new IllegalStateException("Fragment " + this + " not attached to Activity");
        }
        mCheckedForLoaderManager = true;
        mLoaderManager = mActivity.getLoaderManager(mIndex, mLoadersStarted, true);
        mLoaderManager = mActivity.getLoaderManager(mWho, mLoadersStarted, true);
        return mLoaderManager;
    }

@@ -1191,7 +1236,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
     * {@link #setRetainInstance(boolean)} to retain their instance,
     * as this callback tells the fragment when it is fully associated with
     * the new activity instance.  This is called after {@link #onCreateView}
     * and before {@link #onStart()}.
     * and before {@link #onViewStateRestored(Bundle)}.
     * 
     * @param savedInstanceState If the fragment is being re-created from
     * a previous saved state, this is the state.
@@ -1200,6 +1245,21 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
        mCalled = true;
    }

    /**
     * Called when all saved state has been restored into the view hierarchy
     * of the fragment.  This can be used to do initialization based on saved
     * state that you are letting the view hierarchy track itself, such as
     * whether check box widgets are currently checked.  This is called
     * after {@link #onActivityCreated(Bundle)} and before
     * {@link #onStart()}.
     * 
     * @param savedInstanceState If the fragment is being re-created from
     * a previous saved state, this is the state.
     */
    public void onViewStateRestored(Bundle savedInstanceState) {
        mCalled = true;
    }

    /**
     * Called when the Fragment is visible to the user.  This is generally
     * tied to {@link Activity#onStart() Activity.onStart} of the containing
@@ -1212,7 +1272,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
            mLoadersStarted = true;
            if (!mCheckedForLoaderManager) {
                mCheckedForLoaderManager = true;
                mLoaderManager = mActivity.getLoaderManager(mIndex, mLoadersStarted, false);
                mLoaderManager = mActivity.getLoaderManager(mWho, mLoadersStarted, false);
            }
            if (mLoaderManager != null) {
                mLoaderManager.doStart();
@@ -1305,7 +1365,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
        //        + " mLoaderManager=" + mLoaderManager);
        if (!mCheckedForLoaderManager) {
            mCheckedForLoaderManager = true;
            mLoaderManager = mActivity.getLoaderManager(mIndex, mLoadersStarted, false);
            mLoaderManager = mActivity.getLoaderManager(mWho, mLoadersStarted, false);
        }
        if (mLoaderManager != null) {
            mLoaderManager.doDestroy();
@@ -1530,6 +1590,14 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
            writer.print(prefix); writer.print("mActivity=");
                    writer.println(mActivity);
        }
        if (mChildFragmentManager != null) {
            writer.print(prefix); writer.print("mChildFragmentManager=");
                    writer.println(mChildFragmentManager);
        }
        if (mParentFragment != null) {
            writer.print(prefix); writer.print("mParentFragment=");
                    writer.println(mParentFragment);
        }
        if (mArguments != null) {
            writer.print(prefix); writer.print("mArguments="); writer.println(mArguments);
        }
@@ -1564,23 +1632,229 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
            writer.print(prefix); writer.println("Loader Manager:");
            mLoaderManager.dump(prefix + "  ", fd, writer, args);
        }
        if (mChildFragmentManager != null) {
            writer.print(prefix); writer.println("Child Fragment Manager:");
            mChildFragmentManager.dump(prefix + "  ", fd, writer, args);
        }
    }

    Fragment findFragmentByWho(String who) {
        if (who.equals(mWho)) {
            return this;
        }
        if (mChildFragmentManager != null) {
            return mChildFragmentManager.findFragmentByWho(who);
        }
        return null;
    }

    void instantiateChildFragmentManager() {
        mChildFragmentManager = new FragmentManagerImpl();
        mChildFragmentManager.attachActivity(mActivity, new FragmentContainer() {
            @Override
            public View findViewById(int id) {
                if (mView == null) {
                    throw new IllegalStateException("Fragment does not have a view");
                }
                return mView.findViewById(id);
            }
        }, this);
    }

    void performCreate(Bundle savedInstanceState) {
        mCalled = false;
        onCreate(savedInstanceState);
        if (!mCalled) {
            throw new SuperNotCalledException("Fragment " + this
                    + " did not call through to super.onCreate()");
        }
        if (savedInstanceState != null) {
            Parcelable p = savedInstanceState.getParcelable(Activity.FRAGMENTS_TAG);
            if (p != null) {
                if (mChildFragmentManager == null) {
                    instantiateChildFragmentManager();
                }
                mChildFragmentManager.restoreAllState(p, null);
                mChildFragmentManager.dispatchCreate();
            }
        }
    }

    void performActivityCreated(Bundle savedInstanceState) {
        mCalled = false;
        onActivityCreated(savedInstanceState);
        if (!mCalled) {
            throw new SuperNotCalledException("Fragment " + this
                    + " did not call through to super.onActivityCreated()");
        }
        if (mChildFragmentManager != null) {
            mChildFragmentManager.dispatchActivityCreated();
        }
    }

    void performStart() {
        if (mChildFragmentManager != null) {
            mChildFragmentManager.noteStateNotSaved();
            mChildFragmentManager.execPendingActions();
        }
        mCalled = false;
        onStart();
        if (!mCalled) {
            throw new SuperNotCalledException("Fragment " + this
                    + " did not call through to super.onStart()");
        }
        if (mChildFragmentManager != null) {
            mChildFragmentManager.dispatchStart();
        }
        if (mLoaderManager != null) {
            mLoaderManager.doReportStart();
        }
    }

    void performResume() {
        if (mChildFragmentManager != null) {
            mChildFragmentManager.execPendingActions();
        }
        mCalled = false;
        onResume();
        if (!mCalled) {
            throw new SuperNotCalledException("Fragment " + this
                    + " did not call through to super.onResume()");
        }
        if (mChildFragmentManager != null) {
            mChildFragmentManager.dispatchResume();
            mChildFragmentManager.execPendingActions();
        }
    }

    void performConfigurationChanged(Configuration newConfig) {
        onConfigurationChanged(newConfig);
        if (mChildFragmentManager != null) {
            mChildFragmentManager.dispatchConfigurationChanged(newConfig);
        }
    }

    void performLowMemory() {
        onLowMemory();
        if (mChildFragmentManager != null) {
            mChildFragmentManager.dispatchLowMemory();
        }
    }

    void performTrimMemory(int level) {
        onTrimMemory(level);
        if (mChildFragmentManager != null) {
            mChildFragmentManager.dispatchTrimMemory(level);
        }
    }

    boolean performCreateOptionsMenu(Menu menu, MenuInflater inflater) {
        boolean show = false;
        if (!mHidden) {
            if (mHasMenu && mMenuVisible) {
                show = true;
                onCreateOptionsMenu(menu, inflater);
            }
            if (mChildFragmentManager != null) {
                show |= mChildFragmentManager.dispatchCreateOptionsMenu(menu, inflater);
            }
        }
        return show;
    }

    boolean performPrepareOptionsMenu(Menu menu) {
        boolean show = false;
        if (!mHidden) {
            if (mHasMenu && mMenuVisible) {
                show = true;
                onPrepareOptionsMenu(menu);
            }
            if (mChildFragmentManager != null) {
                show |= mChildFragmentManager.dispatchPrepareOptionsMenu(menu);
            }
        }
        return show;
    }

    boolean performOptionsItemSelected(MenuItem item) {
        if (!mHidden) {
            if (mHasMenu && mMenuVisible) {
                if (onOptionsItemSelected(item)) {
                    return true;
                }
            }
            if (mChildFragmentManager != null) {
                if (mChildFragmentManager.dispatchOptionsItemSelected(item)) {
                    return true;
                }
            }
        }
        return false;
    }

    boolean performContextItemSelected(MenuItem item) {
        if (!mHidden) {
            if (onContextItemSelected(item)) {
                return true;
            }
            if (mChildFragmentManager != null) {
                if (mChildFragmentManager.dispatchContextItemSelected(item)) {
                    return true;
                }
            }
        }
        return false;
    }

    void performOptionsMenuClosed(Menu menu) {
        if (!mHidden) {
            if (mHasMenu && mMenuVisible) {
                onOptionsMenuClosed(menu);
            }
            if (mChildFragmentManager != null) {
                mChildFragmentManager.dispatchOptionsMenuClosed(menu);
            }
        }
    }

    void performSaveInstanceState(Bundle outState) {
        onSaveInstanceState(outState);
        if (mChildFragmentManager != null) {
            Parcelable p = mChildFragmentManager.saveAllState();
            if (p != null) {
                outState.putParcelable(Activity.FRAGMENTS_TAG, p);
            }
        }
    }

    void performPause() {
        if (mChildFragmentManager != null) {
            mChildFragmentManager.dispatchPause();
        }
        mCalled = false;
        onPause();
        if (!mCalled) {
            throw new SuperNotCalledException("Fragment " + this
                    + " did not call through to super.onPause()");
        }
    }

    void performStop() {
        if (mChildFragmentManager != null) {
            mChildFragmentManager.dispatchStop();
        }
        mCalled = false;
        onStop();
        if (!mCalled) {
            throw new SuperNotCalledException("Fragment " + this
                    + " did not call through to super.onStop()");
        }
        
        if (mLoadersStarted) {
            mLoadersStarted = false;
            if (!mCheckedForLoaderManager) {
                mCheckedForLoaderManager = true;
                mLoaderManager = mActivity.getLoaderManager(mIndex, mLoadersStarted, false);
                mLoaderManager = mActivity.getLoaderManager(mWho, mLoadersStarted, false);
            }
            if (mLoaderManager != null) {
                if (mActivity == null || !mActivity.mChangingConfigurations) {
@@ -1593,9 +1867,29 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
    }

    void performDestroyView() {
        if (mChildFragmentManager != null) {
            mChildFragmentManager.dispatchDestroyView();
        }
        mCalled = false;
        onDestroyView();
        if (!mCalled) {
            throw new SuperNotCalledException("Fragment " + this
                    + " did not call through to super.onDestroyView()");
        }
        if (mLoaderManager != null) {
            mLoaderManager.doReportNextStart();
        }
    }

    void performDestroy() {
        if (mChildFragmentManager != null) {
            mChildFragmentManager.dispatchDestroy();
        }
        mCalled = false;
        onDestroy();
        if (!mCalled) {
            throw new SuperNotCalledException("Fragment " + this
                    + " did not call through to super.onDestroy()");
        }
    }
}
+68 −79

File changed.

Preview size limit exceeded, changes collapsed.

+4 −2
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@
package android.app;

import android.content.Loader;
import android.content.Loader.OnLoadCanceledListener;
import android.os.Bundle;
import android.util.DebugUtils;
import android.util.Log;
@@ -213,6 +212,8 @@ class LoaderManagerImpl extends LoaderManager {
    // previously run loader until the new loader's data is available.
    final SparseArray<LoaderInfo> mInactiveLoaders = new SparseArray<LoaderInfo>();

    final String mWho;

    Activity mActivity;
    boolean mStarted;
    boolean mRetaining;
@@ -529,7 +530,8 @@ class LoaderManagerImpl extends LoaderManager {
        }
    }
    
    LoaderManagerImpl(Activity activity, boolean started) {
    LoaderManagerImpl(String who, Activity activity, boolean started) {
        mWho = who;
        mActivity = activity;
        mStarted = started;
    }