summaryrefslogtreecommitdiffstats
path: root/core/java/android/app
diff options
context:
space:
mode:
authorDianne Hackborn <hackbod@google.com>2012-09-04 18:48:15 -0700
committerDianne Hackborn <hackbod@google.com>2012-09-06 11:05:53 -0700
commit62bea2f1710be0d1a42c07109fd4307ded660d3b (patch)
treef772341cd06cd3df43bea1572361d226f4faed2f /core/java/android/app
parent18e876806718e28edaa3cd9bb0262a9b400bc82b (diff)
downloadframeworks_base-62bea2f1710be0d1a42c07109fd4307ded660d3b.zip
frameworks_base-62bea2f1710be0d1a42c07109fd4307ded660d3b.tar.gz
frameworks_base-62bea2f1710be0d1a42c07109fd4307ded660d3b.tar.bz2
Nested fragments.
Change-Id: I79acc19b391352c16b06afee2ca543223c38e364
Diffstat (limited to 'core/java/android/app')
-rw-r--r--core/java/android/app/Activity.java70
-rw-r--r--core/java/android/app/Fragment.java318
-rw-r--r--core/java/android/app/FragmentManager.java147
-rw-r--r--core/java/android/app/LoaderManager.java6
4 files changed, 423 insertions, 118 deletions
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 99dfccb..05b04dc 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -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);
- if (lm.mRetaining) {
- retainLoaders = true;
- } else {
- lm.doDestroy();
- mAllLoaderManagers.removeAt(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.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,10 +5096,14 @@ public class Activity extends ContextThemeWrapper
}
mFragments.dispatchStart();
if (mAllLoaderManagers != null) {
- for (int i=mAllLoaderManagers.size()-1; i>=0; i--) {
- LoaderManagerImpl lm = mAllLoaderManagers.valueAt(i);
- lm.finishRetain();
- lm.doReportStart();
+ 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();
+ }
}
}
}
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 28876d3..3ff9df5 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -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
@@ -412,7 +414,13 @@ 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,16 +603,26 @@ 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;
- mWho = "android:fragment:" + mIndex;
+ if (parent != null) {
+ mWho = parent.mWho + ":" + mIndex;
+ } else {
+ mWho = "android:fragment:" + mIndex;
+ }
}
final boolean isInBackStack() {
@@ -785,12 +803,35 @@ 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.
*/
final public boolean isAdded() {
@@ -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.
@@ -1199,7 +1244,22 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
public void onActivityCreated(Bundle savedInstanceState) {
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()");
+ }
+ }
}
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 52a6557..eaaf0d7 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -20,7 +20,6 @@ import android.animation.Animator;
import android.animation.AnimatorInflater;
import android.animation.AnimatorListenerAdapter;
import android.content.res.Configuration;
-import android.content.res.Resources;
import android.content.res.TypedArray;
import android.os.Bundle;
import android.os.Handler;
@@ -30,7 +29,6 @@ import android.os.Parcelable;
import android.util.DebugUtils;
import android.util.Log;
import android.util.LogWriter;
-import android.util.Slog;
import android.util.SparseArray;
import android.view.Menu;
import android.view.MenuInflater;
@@ -381,6 +379,13 @@ final class FragmentManagerState implements Parcelable {
}
/**
+ * Callbacks from FragmentManagerImpl to its container.
+ */
+interface FragmentContainer {
+ public View findViewById(int id);
+}
+
+/**
* Container for fragments associated with an activity.
*/
final class FragmentManagerImpl extends FragmentManager {
@@ -410,6 +415,8 @@ final class FragmentManagerImpl extends FragmentManager {
int mCurState = Fragment.INITIALIZING;
Activity mActivity;
+ FragmentContainer mContainer;
+ Fragment mParent;
boolean mNeedMenuInvalidate;
boolean mStateSaved;
@@ -585,7 +592,11 @@ final class FragmentManagerImpl extends FragmentManager {
sb.append("FragmentManager{");
sb.append(Integer.toHexString(System.identityHashCode(this)));
sb.append(" in ");
- DebugUtils.buildShortClassTag(mActivity, sb);
+ if (mParent != null) {
+ DebugUtils.buildShortClassTag(mParent, sb);
+ } else {
+ DebugUtils.buildShortClassTag(mActivity, sb);
+ }
sb.append("}}");
return sb.toString();
}
@@ -681,6 +692,11 @@ final class FragmentManagerImpl extends FragmentManager {
}
writer.print(prefix); writer.println("FragmentManager misc state:");
+ writer.print(prefix); writer.print(" mActivity="); writer.println(mActivity);
+ writer.print(prefix); writer.print(" mContainer="); writer.println(mContainer);
+ if (mParent != null) {
+ writer.print(prefix); writer.print(" mParent="); writer.println(mParent);
+ }
writer.print(prefix); writer.print(" mCurState="); writer.print(mCurState);
writer.print(" mStateSaved="); writer.print(mStateSaved);
writer.print(" mDestroyed="); writer.println(mDestroyed);
@@ -809,7 +825,9 @@ final class FragmentManagerImpl extends FragmentManager {
}
}
f.mActivity = mActivity;
- f.mFragmentManager = mActivity.mFragments;
+ f.mParentFragment = mParent;
+ f.mFragmentManager = mParent != null
+ ? mParent.mChildFragmentManager : mActivity.mFragments;
f.mCalled = false;
f.onAttach(mActivity);
if (!f.mCalled) {
@@ -817,14 +835,9 @@ final class FragmentManagerImpl extends FragmentManager {
+ " did not call through to super.onAttach()");
}
mActivity.onAttachFragment(f);
-
+
if (!f.mRetaining) {
- f.mCalled = false;
- f.onCreate(f.mSavedFragmentState);
- if (!f.mCalled) {
- throw new SuperNotCalledException("Fragment " + f
- + " did not call through to super.onCreate()");
- }
+ f.performCreate(f.mSavedFragmentState);
}
f.mRetaining = false;
if (f.mFromLayout) {
@@ -845,7 +858,7 @@ final class FragmentManagerImpl extends FragmentManager {
if (!f.mFromLayout) {
ViewGroup container = null;
if (f.mContainerId != 0) {
- container = (ViewGroup)mActivity.findViewById(f.mContainerId);
+ container = (ViewGroup)mContainer.findViewById(f.mContainerId);
if (container == null && !f.mRestored) {
throwException(new IllegalArgumentException(
"No view found for id 0x"
@@ -873,14 +886,9 @@ final class FragmentManagerImpl extends FragmentManager {
}
}
- f.mCalled = false;
- f.onActivityCreated(f.mSavedFragmentState);
- if (!f.mCalled) {
- throw new SuperNotCalledException("Fragment " + f
- + " did not call through to super.onActivityCreated()");
- }
+ f.performActivityCreated(f.mSavedFragmentState);
if (f.mView != null) {
- f.restoreViewState();
+ f.restoreViewState(f.mSavedFragmentState);
}
f.mSavedFragmentState = null;
}
@@ -888,23 +896,13 @@ final class FragmentManagerImpl extends FragmentManager {
case Fragment.STOPPED:
if (newState > Fragment.STOPPED) {
if (DEBUG) Log.v(TAG, "moveto STARTED: " + f);
- f.mCalled = false;
f.performStart();
- if (!f.mCalled) {
- throw new SuperNotCalledException("Fragment " + f
- + " did not call through to super.onStart()");
- }
}
case Fragment.STARTED:
if (newState > Fragment.STARTED) {
if (DEBUG) Log.v(TAG, "moveto RESUMED: " + f);
- f.mCalled = false;
f.mResumed = true;
- f.onResume();
- if (!f.mCalled) {
- throw new SuperNotCalledException("Fragment " + f
- + " did not call through to super.onResume()");
- }
+ f.performResume();
// Get rid of this in case we saved it and never needed it.
f.mSavedFragmentState = null;
f.mSavedViewState = null;
@@ -915,23 +913,13 @@ final class FragmentManagerImpl extends FragmentManager {
case Fragment.RESUMED:
if (newState < Fragment.RESUMED) {
if (DEBUG) Log.v(TAG, "movefrom RESUMED: " + f);
- f.mCalled = false;
- f.onPause();
- if (!f.mCalled) {
- throw new SuperNotCalledException("Fragment " + f
- + " did not call through to super.onPause()");
- }
+ f.performPause();
f.mResumed = false;
}
case Fragment.STARTED:
if (newState < Fragment.STARTED) {
if (DEBUG) Log.v(TAG, "movefrom STARTED: " + f);
- f.mCalled = false;
f.performStop();
- if (!f.mCalled) {
- throw new SuperNotCalledException("Fragment " + f
- + " did not call through to super.onStop()");
- }
}
case Fragment.STOPPED:
case Fragment.ACTIVITY_CREATED:
@@ -944,12 +932,7 @@ final class FragmentManagerImpl extends FragmentManager {
saveFragmentViewState(f);
}
}
- f.mCalled = false;
f.performDestroyView();
- if (!f.mCalled) {
- throw new SuperNotCalledException("Fragment " + f
- + " did not call through to super.onDestroyView()");
- }
if (f.mView != null && f.mContainer != null) {
Animator anim = null;
if (mCurState > Fragment.INITIALIZING && !mDestroyed) {
@@ -1008,12 +991,7 @@ final class FragmentManagerImpl extends FragmentManager {
} else {
if (DEBUG) Log.v(TAG, "movefrom CREATED: " + f);
if (!f.mRetaining) {
- f.mCalled = false;
- f.onDestroy();
- if (!f.mCalled) {
- throw new SuperNotCalledException("Fragment " + f
- + " did not call through to super.onDestroy()");
- }
+ f.performDestroy();
}
f.mCalled = false;
@@ -1027,6 +1005,7 @@ final class FragmentManagerImpl extends FragmentManager {
makeInactive(f);
} else {
f.mActivity = null;
+ f.mParentFragment = null;
f.mFragmentManager = null;
}
}
@@ -1050,11 +1029,11 @@ final class FragmentManagerImpl extends FragmentManager {
if (mActivity == null && newState != Fragment.INITIALIZING) {
throw new IllegalStateException("No activity");
}
-
+
if (!always && mCurState == newState) {
return;
}
-
+
mCurState = newState;
if (mActive != null) {
boolean loadersRunning = false;
@@ -1099,11 +1078,11 @@ final class FragmentManagerImpl extends FragmentManager {
if (mActive == null) {
mActive = new ArrayList<Fragment>();
}
- f.setIndex(mActive.size());
+ f.setIndex(mActive.size(), mParent);
mActive.add(f);
} else {
- f.setIndex(mAvailIndices.remove(mAvailIndices.size()-1));
+ f.setIndex(mAvailIndices.remove(mAvailIndices.size()-1), mParent);
mActive.set(f.mIndex, f);
}
if (DEBUG) Log.v(TAG, "Allocated fragment index " + f);
@@ -1120,7 +1099,7 @@ final class FragmentManagerImpl extends FragmentManager {
mAvailIndices = new ArrayList<Integer>();
}
mAvailIndices.add(f.mIndex);
- mActivity.invalidateFragmentIndex(f.mIndex);
+ mActivity.invalidateFragment(f.mWho);
f.initState();
}
@@ -1296,7 +1275,7 @@ final class FragmentManagerImpl extends FragmentManager {
if (mActive != null && who != null) {
for (int i=mActive.size()-1; i>=0; i--) {
Fragment f = mActive.get(i);
- if (f != null && who.equals(f.mWho)) {
+ if (f != null && (f=f.findFragmentByWho(who)) != null) {
return f;
}
}
@@ -1566,7 +1545,7 @@ final class FragmentManagerImpl extends FragmentManager {
if (mStateBundle == null) {
mStateBundle = new Bundle();
}
- f.onSaveInstanceState(mStateBundle);
+ f.performSaveInstanceState(mStateBundle);
if (!mStateBundle.isEmpty()) {
result = mStateBundle;
mStateBundle = null;
@@ -1735,7 +1714,7 @@ final class FragmentManagerImpl extends FragmentManager {
for (int i=0; i<fms.mActive.length; i++) {
FragmentState fs = fms.mActive[i];
if (fs != null) {
- Fragment f = fs.instantiate(mActivity);
+ Fragment f = fs.instantiate(mActivity, mParent);
if (DEBUG) Log.v(TAG, "restoreAllState: adding #" + i + ": " + f);
mActive.add(f);
// Now that the fragment is instantiated (or came from being
@@ -1803,9 +1782,11 @@ final class FragmentManagerImpl extends FragmentManager {
}
}
- public void attachActivity(Activity activity) {
+ public void attachActivity(Activity activity, FragmentContainer container, Fragment parent) {
if (mActivity != null) throw new IllegalStateException("Already attached");
mActivity = activity;
+ mContainer = container;
+ mParent = parent;
}
public void noteStateNotSaved() {
@@ -1840,11 +1821,17 @@ final class FragmentManagerImpl extends FragmentManager {
moveToState(Fragment.STOPPED, false);
}
+ public void dispatchDestroyView() {
+ moveToState(Fragment.CREATED, false);
+ }
+
public void dispatchDestroy() {
mDestroyed = true;
execPendingActions();
moveToState(Fragment.INITIALIZING, false);
mActivity = null;
+ mContainer = null;
+ mParent = null;
}
public void dispatchConfigurationChanged(Configuration newConfig) {
@@ -1852,7 +1839,7 @@ final class FragmentManagerImpl extends FragmentManager {
for (int i=0; i<mAdded.size(); i++) {
Fragment f = mAdded.get(i);
if (f != null) {
- f.onConfigurationChanged(newConfig);
+ f.performConfigurationChanged(newConfig);
}
}
}
@@ -1863,7 +1850,7 @@ final class FragmentManagerImpl extends FragmentManager {
for (int i=0; i<mAdded.size(); i++) {
Fragment f = mAdded.get(i);
if (f != null) {
- f.onLowMemory();
+ f.performLowMemory();
}
}
}
@@ -1874,7 +1861,7 @@ final class FragmentManagerImpl extends FragmentManager {
for (int i=0; i<mAdded.size(); i++) {
Fragment f = mAdded.get(i);
if (f != null) {
- f.onTrimMemory(level);
+ f.performTrimMemory(level);
}
}
}
@@ -1886,13 +1873,14 @@ final class FragmentManagerImpl extends FragmentManager {
if (mAdded != null) {
for (int i=0; i<mAdded.size(); i++) {
Fragment f = mAdded.get(i);
- if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) {
- show = true;
- f.onCreateOptionsMenu(menu, inflater);
- if (newMenus == null) {
- newMenus = new ArrayList<Fragment>();
+ if (f != null) {
+ if (f.performCreateOptionsMenu(menu, inflater)) {
+ show = true;
+ if (newMenus == null) {
+ newMenus = new ArrayList<Fragment>();
+ }
+ newMenus.add(f);
}
- newMenus.add(f);
}
}
}
@@ -1916,9 +1904,10 @@ final class FragmentManagerImpl extends FragmentManager {
if (mAdded != null) {
for (int i=0; i<mAdded.size(); i++) {
Fragment f = mAdded.get(i);
- if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) {
- show = true;
- f.onPrepareOptionsMenu(menu);
+ if (f != null) {
+ if (f.performPrepareOptionsMenu(menu)) {
+ show = true;
+ }
}
}
}
@@ -1929,8 +1918,8 @@ final class FragmentManagerImpl extends FragmentManager {
if (mAdded != null) {
for (int i=0; i<mAdded.size(); i++) {
Fragment f = mAdded.get(i);
- if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) {
- if (f.onOptionsItemSelected(item)) {
+ if (f != null) {
+ if (f.performOptionsItemSelected(item)) {
return true;
}
}
@@ -1943,8 +1932,8 @@ final class FragmentManagerImpl extends FragmentManager {
if (mAdded != null) {
for (int i=0; i<mAdded.size(); i++) {
Fragment f = mAdded.get(i);
- if (f != null && !f.mHidden) {
- if (f.onContextItemSelected(item)) {
+ if (f != null) {
+ if (f.performContextItemSelected(item)) {
return true;
}
}
@@ -1957,8 +1946,8 @@ final class FragmentManagerImpl extends FragmentManager {
if (mAdded != null) {
for (int i=0; i<mAdded.size(); i++) {
Fragment f = mAdded.get(i);
- if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible) {
- f.onOptionsMenuClosed(menu);
+ if (f != null) {
+ f.performOptionsMenuClosed(menu);
}
}
}
diff --git a/core/java/android/app/LoaderManager.java b/core/java/android/app/LoaderManager.java
index ff71ee7..fd0f0bf 100644
--- a/core/java/android/app/LoaderManager.java
+++ b/core/java/android/app/LoaderManager.java
@@ -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;
}