More fragment stuff:

- New startActivityForResult() API.
- Fragments now should have the correct lifecycle while hanging around
  in the back stack (not being destroyed and re-created).
- Rework of state save/restore to make it simpler and better.  In theory
  now any fragment (including layout and others in the hierarchy) can
  now be retained across config changes, though this hasn't been tested.

Change-Id: I2a7fe560e14e567f5675a2f172a23fca67b3e97f
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 5b0af67..174c15b 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -16,7 +16,6 @@
 
 package android.app;
 
-import java.lang.reflect.Constructor;
 import java.util.ArrayList;
 import java.util.HashMap;
 
@@ -3162,6 +3161,36 @@
     }
 
     /**
+     * This is called when a Fragment in this activity calls its 
+     * {@link Fragment#startActivity} or {@link Fragment#startActivityForResult}
+     * method.
+     * 
+     * <p>This method throws {@link android.content.ActivityNotFoundException}
+     * if there was no Activity found to run the given Intent.
+     * 
+     * @param fragment The fragment making the call.
+     * @param intent The intent to start.
+     * @param requestCode Reply request code.  < 0 if reply is not requested. 
+     * 
+     * @throws android.content.ActivityNotFoundException
+     * 
+     * @see Fragment#startActivity 
+     * @see Fragment#startActivityForResult 
+     */
+    public void startActivityFromFragment(Fragment fragment, Intent intent, 
+            int requestCode) {
+        Instrumentation.ActivityResult ar =
+            mInstrumentation.execStartActivity(
+                this, mMainThread.getApplicationThread(), mToken, fragment,
+                intent, requestCode);
+        if (ar != null) {
+            mMainThread.sendActivityResult(
+                mToken, fragment.mWho, requestCode,
+                ar.getResultCode(), ar.getResultData());
+        }
+    }
+
+    /**
      * Like {@link #startActivityFromChild(Activity, Intent, int)}, but
      * taking a IntentSender; see
      * {@link #startIntentSenderForResult(IntentSender, int, Intent, int, int, int)}
@@ -3433,8 +3462,7 @@
      * @see #createPendingResult
      * @see #setResult(int)
      */
-    protected void onActivityResult(int requestCode, int resultCode,
-            Intent data) {
+    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
     }
 
     /**
@@ -3854,9 +3882,14 @@
                 fragment.mFromLayout = true;
                 fragment.mFragmentId = id;
                 fragment.mTag = tag;
-                fragment.onInflate(this, attrs);
                 mFragments.addFragment(fragment, true);
             }
+            // If this fragment is newly instantiated (either right now, or
+            // from last saved state), then give it the attributes to
+            // initialize itself.
+            if (!fragment.mRetaining) {
+                fragment.onInflate(this, attrs, fragment.mSavedFragmentState);
+            }
             if (fragment.mView == null) {
                 throw new IllegalStateException("Fragment " + fname
                         + " did not create a view.");
@@ -4059,6 +4092,11 @@
             + ", resCode=" + resultCode + ", data=" + data);
         if (who == null) {
             onActivityResult(requestCode, resultCode, data);
+        } else {
+            Fragment frag = mFragments.findFragmentByWho(who);
+            if (frag != null) {
+                frag.onActivityResult(requestCode, resultCode, data);
+            }
         }
     }
 }
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 2f6d9f2..5217f5e 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -620,7 +620,8 @@
                     + " Is this really what you want?");
         }
         mMainThread.getInstrumentation().execStartActivity(
-            getOuterContext(), mMainThread.getApplicationThread(), null, null, intent, -1);
+            getOuterContext(), mMainThread.getApplicationThread(), null,
+            (Activity)null, intent, -1);
     }
 
     @Override
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 1b877b2..c64b3e8 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -17,6 +17,7 @@
 package android.app;
 
 import android.content.ComponentCallbacks;
+import android.content.Intent;
 import android.content.res.Configuration;
 import android.os.Bundle;
 import android.os.Parcel;
@@ -36,8 +37,8 @@
     static final String VIEW_STATE_TAG = "android:view_state";
     
     final String mClassName;
+    final int mIndex;
     final boolean mFromLayout;
-    final int mSavedStateId;
     final int mFragmentId;
     final int mContainerId;
     final String mTag;
@@ -49,8 +50,8 @@
     
     public FragmentState(Fragment frag) {
         mClassName = frag.getClass().getName();
+        mIndex = frag.mIndex;
         mFromLayout = frag.mFromLayout;
-        mSavedStateId = frag.mSavedStateId;
         mFragmentId = frag.mFragmentId;
         mContainerId = frag.mContainerId;
         mTag = frag.mTag;
@@ -59,8 +60,8 @@
     
     public FragmentState(Parcel in) {
         mClassName = in.readString();
+        mIndex = in.readInt();
         mFromLayout = in.readInt() != 0;
-        mSavedStateId = in.readInt();
         mFragmentId = in.readInt();
         mContainerId = in.readInt();
         mTag = in.readString();
@@ -69,10 +70,6 @@
     }
     
     public Fragment instantiate(Activity activity) {
-        if (mFromLayout) {
-            return null;
-        }
-        
         if (mInstance != null) {
             return mInstance;
         }
@@ -89,7 +86,8 @@
             mInstance.mSavedViewState
                     = mSavedFragmentState.getSparseParcelableArray(VIEW_STATE_TAG);
         }
-        mInstance.mSavedStateId = mSavedStateId;
+        mInstance.setIndex(mIndex);
+        mInstance.mFromLayout = mFromLayout;
         mInstance.mFragmentId = mFragmentId;
         mInstance.mContainerId = mContainerId;
         mInstance.mTag = mTag;
@@ -104,8 +102,8 @@
 
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeString(mClassName);
+        dest.writeInt(mIndex);
         dest.writeInt(mFromLayout ? 1 : 0);
-        dest.writeInt(mSavedStateId);
         dest.writeInt(mFragmentId);
         dest.writeInt(mContainerId);
         dest.writeString(mTag);
@@ -149,6 +147,15 @@
     Bundle mSavedFragmentState;
     SparseArray<Parcelable> mSavedViewState;
     
+    // Index into active fragment array.
+    int mIndex = -1;
+    
+    // Internal unique name for this fragment;
+    String mWho;
+    
+    // True if the fragment is in the list of added fragments.
+    boolean mAdded;
+    
     // Set to true if this fragment was instantiated from a layout file.
     boolean mFromLayout;
     
@@ -187,10 +194,6 @@
     // The View generated for this fragment.
     View mView;
     
-    // Used for performing save state of fragments.
-    int mSavedStateSeq = 0;
-    int mSavedStateId;
-    
     public Fragment() {
     }
 
@@ -217,6 +220,16 @@
         }
     }
     
+    void setIndex(int index) {
+        mIndex = index;
+        mWho = "android:fragment:" + mIndex;
+   }
+    
+    void clearIndex() {
+        mIndex = -1;
+        mWho = null;
+    }
+    
     /**
      * Subclasses can not override equals().
      */
@@ -277,14 +290,56 @@
     }
     
     /**
+     * Call {@link Activity#startActivity(Intent)} on the fragment's
+     * containing Activity.
+     */
+    public void startActivity(Intent intent) {
+        mActivity.startActivityFromFragment(this, intent, -1);
+    }
+    
+    /**
+     * Call {@link Activity#startActivityForResult(Intent, int)} on the fragment's
+     * containing Activity.
+     */
+    public void startActivityForResult(Intent intent, int requestCode) {
+        mActivity.startActivityFromFragment(this, intent, requestCode);
+    }
+    
+    /**
+     * Receive the result from a previous call to
+     * {@link #startActivityForResult(Intent, int)}.  This follows the
+     * related Activity API as described there in
+     * {@link Activity#onActivityResult(int, int, Intent)}.
+     * 
+     * @param requestCode The integer request code originally supplied to
+     *                    startActivityForResult(), allowing you to identify who this
+     *                    result came from.
+     * @param resultCode The integer result code returned by the child activity
+     *                   through its setResult().
+     * @param data An Intent, which can return result data to the caller
+     *               (various data can be attached to Intent "extras").
+     */
+    public void onActivityResult(int requestCode, int resultCode, Intent data) {
+    }
+    
+    /**
      * Called when a fragment is being created as part of a view layout
-     * inflation, typically from setting the content view of an activity.
+     * inflation, typically from setting the content view of an activity.  This
+     * will be called both the first time the fragment is created, as well
+     * later when it is being re-created from its saved state (which is also
+     * given here).
+     * 
+     * XXX This is kind-of yucky...  maybe we could just supply the
+     * AttributeSet to onCreate()?
      * 
      * @param activity The Activity that is inflating the fragment.
      * @param attrs The attributes at the tag where the fragment is
      * being created.
+     * @param savedInstanceState If the fragment is being re-created from
+     * a previous saved state, this is the state.
      */
-    public void onInflate(Activity activity, AttributeSet attrs) {
+    public void onInflate(Activity activity, AttributeSet attrs,
+            Bundle savedInstanceState) {
         mCalled = true;
     }
     
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index 0bc1b832..7556718 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -27,7 +27,6 @@
 import android.view.animation.AnimationUtils;
 
 import java.util.ArrayList;
-import java.util.HashMap;
 
 final class BackStackEntry implements FragmentTransaction, Runnable {
     final FragmentManager mManager;
@@ -68,9 +67,9 @@
         if (containerViewId == 0) {
             throw new IllegalArgumentException("Must use non-zero containerViewId");
         }
-        if (mManager.mFragments != null) {
-            for (int i=0; i<mManager.mFragments.size(); i++) {
-                Fragment old = mManager.mFragments.get(i);
+        if (mManager.mAdded != null) {
+            for (int i=0; i<mManager.mAdded.size(); i++) {
+                Fragment old = mManager.mAdded.get(i);
                 if (old.mContainerId == containerViewId) {
                     remove(old);
                 }
@@ -118,17 +117,20 @@
     public void run() {
         if (mRemoved != null) {
             for (int i=mRemoved.size()-1; i>=0; i--) {
-                mManager.removeFragment(mRemoved.get(i), mTransition,
-                        mTransitionStyle);
+                Fragment f = mRemoved.get(i);
+                if (mAddToBackStack) {
+                    f.mBackStackNesting++;
+                }
+                mManager.removeFragment(f, mTransition, mTransitionStyle);
             }
         }
         if (mAdded != null) {
             for (int i=mAdded.size()-1; i>=0; i--) {
                 Fragment f = mAdded.get(i);
-                mManager.addFragment(f, false);
                 if (mAddToBackStack) {
                     f.mBackStackNesting++;
                 }
+                mManager.addFragment(f, false);
             }
         }
         mManager.moveToState(mManager.mCurState, mTransition,
@@ -152,7 +154,11 @@
         }
         if (mRemoved != null) {
             for (int i=mRemoved.size()-1; i>=0; i--) {
-                mManager.addFragment(mRemoved.get(i), false);
+                Fragment f = mRemoved.get(i);
+                if (mAddToBackStack) {
+                    f.mBackStackNesting--;
+                }
+                mManager.addFragment(f, false);
             }
         }
     }
@@ -208,8 +214,7 @@
         final int N = frags.size();
         int[] ids = new int[N];
         for (int i=0; i<N; i++) {
-            FragmentState fs = fm.saveFragment(frags.get(i));
-            ids[i] = fs.mSavedStateId;
+            ids[i] = frags.get(i).mIndex;
         }
         return ids;
     }
@@ -219,7 +224,9 @@
         final int N = states.length;
         ArrayList<Fragment> frags = new ArrayList<Fragment>(N);
         for (int i=0; i<N; i++) {
-            frags.add(fm.mRestoredFragments.get(states[i]).instantiate(fm.mActivity));
+            Fragment f = fm.mActive.get(states[i]);
+            f.mBackStackNesting++;
+            frags.add(f);
         }
         return frags;
     }
@@ -249,7 +256,7 @@
 }
 
 final class FragmentManagerState implements Parcelable {
-    FragmentState[] mFragments;
+    FragmentState[] mActive;
     int[] mAdded;
     BackStackState[] mBackStack;
     
@@ -257,7 +264,7 @@
     }
     
     public FragmentManagerState(Parcel in) {
-        mFragments = in.createTypedArray(FragmentState.CREATOR);
+        mActive = in.createTypedArray(FragmentState.CREATOR);
         mAdded = in.createIntArray();
         mBackStack = in.createTypedArray(BackStackState.CREATOR);
     }
@@ -267,7 +274,7 @@
     }
 
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeTypedArray(mFragments, flags);
+        dest.writeTypedArray(mActive, flags);
         dest.writeIntArray(mAdded);
         dest.writeTypedArray(mBackStack, flags);
     }
@@ -289,18 +296,15 @@
  * Container for fragments associated with an activity.
  */
 public class FragmentManager {
-    ArrayList<Fragment> mFragments;
+    ArrayList<Fragment> mActive;
+    ArrayList<Fragment> mAdded;
+    ArrayList<Integer> mAvailIndices;
     ArrayList<BackStackEntry> mBackStack;
     
     int mCurState = Fragment.INITIALIZING;
     Activity mActivity;
     
-    int mSaveStateSeq = 0;
-    
     // Temporary vars for state save and restore.
-    int mCurSaveId = 0;
-    HashMap<Fragment, FragmentState> mSavedFragments;
-    SparseArray<FragmentState> mRestoredFragments;
     Bundle mStateBundle = null;
     SparseArray<Parcelable> mStateArray = null;
     
@@ -340,6 +344,11 @@
     }
     
     void moveToState(Fragment f, int newState, int transit, int transitionStyle) {
+        // Fragments that are not currently added will sit in the onCreate() state.
+        if (!f.mAdded && newState > Fragment.CREATED) {
+            newState = Fragment.CREATED;
+        }
+        
         if (f.mState < newState) {
             switch (f.mState) {
                 case Fragment.INITIALIZING:
@@ -366,9 +375,13 @@
                         // and the inflater will take care of adding it.
                         f.mView = f.onCreateView(mActivity.getLayoutInflater(),
                                 null, f.mSavedFragmentState);
+                        if (f.mView != null) {
+                            f.mView.setSaveFromParentEnabled(false);
+                            f.restoreViewState();
+                        }
                     }
-                case Fragment.CONTENT:
-                    if (newState > Fragment.CONTENT) {
+                case Fragment.CREATED:
+                    if (newState > Fragment.CREATED) {
                         if (!f.mFromLayout) {
                             ViewGroup container = null;
                             if (f.mContainerId != 0) {
@@ -404,8 +417,8 @@
                         }
                         f.mSavedFragmentState = null;
                     }
-                case Fragment.CREATED:
-                    if (newState > Fragment.CREATED) {
+                case Fragment.CONTENT:
+                    if (newState > Fragment.CONTENT) {
                         f.mCalled = false;
                         f.onStart();
                         if (!f.mCalled) {
@@ -448,7 +461,7 @@
                         if (f.mView != null) {
                             // Need to save the current view state if not
                             // done already.
-                            if (!mActivity.isFinishing()) {
+                            if (!mActivity.isFinishing() && f.mSavedFragmentState == null) {
                                 saveFragmentViewState(f);
                             }
                             if (f.mContainer != null) {
@@ -504,34 +517,75 @@
         }
         
         mCurState = newState;
-        if (mFragments != null) {
-            for (int i=0; i<mFragments.size(); i++) {
-                Fragment f = mFragments.get(i);
-                moveToState(f, newState, transit, transitStyle);
+        if (mActive != null) {
+            for (int i=0; i<mActive.size(); i++) {
+                Fragment f = mActive.get(i);
+                if (f != null) {
+                    moveToState(f, newState, transit, transitStyle);
+                }
             }
         }
     }
     
-    public void addFragment(Fragment fragment, boolean moveToStateNow) {
-        if (mFragments == null) {
-            mFragments = new ArrayList<Fragment>();
+    void makeActive(Fragment f) {
+        if (f.mIndex >= 0) {
+            return;
         }
-        mFragments.add(fragment);
+        
+        if (mAvailIndices == null || mAvailIndices.size() <= 0) {
+            if (mActive == null) {
+                mActive = new ArrayList<Fragment>();
+            }
+            f.setIndex(mActive.size());
+            mActive.add(f);
+            
+        } else {
+            f.setIndex(mAvailIndices.remove(mAvailIndices.size()-1));
+            mActive.set(f.mIndex, f);
+        }
+    }
+    
+    void makeInactive(Fragment f) {
+        if (f.mIndex < 0) {
+            return;
+        }
+        
+        mActive.set(f.mIndex, null);
+        if (mAvailIndices == null) {
+            mAvailIndices = new ArrayList<Integer>();
+        }
+        mAvailIndices.add(f.mIndex);
+        f.clearIndex();
+    }
+    
+    public void addFragment(Fragment fragment, boolean moveToStateNow) {
+        if (mAdded == null) {
+            mAdded = new ArrayList<Fragment>();
+        }
+        mAdded.add(fragment);
+        makeActive(fragment);
+        fragment.mAdded = true;
         if (moveToStateNow) {
             moveToState(fragment, mCurState, 0, 0);
         }
     }
     
     public void removeFragment(Fragment fragment, int transition, int transitionStyle) {
-        mFragments.remove(fragment);
-        moveToState(fragment, Fragment.INITIALIZING, transition, transitionStyle);
+        mAdded.remove(fragment);
+        final boolean inactive = fragment.mBackStackNesting <= 0;
+        if (inactive) {
+            makeInactive(fragment);
+        }
+        fragment.mAdded = false;
+        moveToState(fragment, inactive ? Fragment.INITIALIZING : Fragment.CREATED,
+                transition, transitionStyle);
     }
     
     public Fragment findFragmentById(int id) {
-        if (mFragments != null) {
-            for (int i=mFragments.size()-1; i>=0; i--) {
-                Fragment f = mFragments.get(i);
-                if (f.mFragmentId == id) {
+        if (mActive != null) {
+            for (int i=mActive.size()-1; i>=0; i--) {
+                Fragment f = mActive.get(i);
+                if (f != null && f.mFragmentId == id) {
                     return f;
                 }
             }
@@ -540,10 +594,22 @@
     }
     
     public Fragment findFragmentByTag(String tag) {
-        if (mFragments != null && tag != null) {
-            for (int i=mFragments.size()-1; i>=0; i--) {
-                Fragment f = mFragments.get(i);
-                if (tag.equals(f.mTag)) {
+        if (mActive != null && tag != null) {
+            for (int i=mActive.size()-1; i>=0; i--) {
+                Fragment f = mActive.get(i);
+                if (f != null && tag.equals(f.mTag)) {
+                    return f;
+                }
+            }
+        }
+        return null;
+    }
+    
+    public Fragment findFragmentByWho(String who) {
+        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)) {
                     return f;
                 }
             }
@@ -605,10 +671,10 @@
     
     ArrayList<Fragment> retainNonConfig() {
         ArrayList<Fragment> fragments = null;
-        if (mFragments != null) {
-            for (int i=0; i<mFragments.size(); i++) {
-                Fragment f = mFragments.get(i);
-                if (f.mBackStackNesting <= 0 && f.mRetainInstance && f.mTag != null) {
+        if (mActive != null) {
+            for (int i=0; i<mActive.size(); i++) {
+                Fragment f = mActive.get(i);
+                if (f != null && f.mRetainInstance) {
                     if (fragments == null) {
                         fragments = new ArrayList<Fragment>();
                     }
@@ -621,7 +687,7 @@
     }
     
     void saveFragmentViewState(Fragment f) {
-        if (f.mSavedViewState != null) {
+        if (f.mView == null) {
             return;
         }
         if (mStateArray == null) {
@@ -634,62 +700,59 @@
         }
     }
     
-    FragmentState saveFragment(Fragment f) {
-        if (mSavedFragments != null) {
-            FragmentState fs = mSavedFragments.get(f);
-            if (fs != null) {
-                return fs;
-            }
-        } else {
-            mSavedFragments = new HashMap<Fragment, FragmentState>();
-        }
-        
-        f.mSavedStateSeq = mSaveStateSeq;
-        f.mSavedStateId = ++mCurSaveId;
-        
-        FragmentState fs = new FragmentState(f);
-        mSavedFragments.put(f, fs);
-        
-        if (mStateBundle == null) {
-            mStateBundle = new Bundle();
-        }
-        f.onSaveInstanceState(mStateBundle);
-        if (!mStateBundle.isEmpty()) {
-            fs.mSavedFragmentState = mStateBundle;
-            mStateBundle = null;
-        }
-        
-        if (f.mView != null) {
-            saveFragmentViewState(f);
-            if (f.mSavedViewState != null) {
-                if (fs.mSavedFragmentState == null) {
-                    fs.mSavedFragmentState = new Bundle();
-                }
-                fs.mSavedFragmentState.putSparseParcelableArray(
-                        FragmentState.VIEW_STATE_TAG, f.mSavedViewState);
-            }
-        }
-        
-        return fs;
-    }
-    
     Parcelable saveAllState() {
-        mSavedFragments = null;
-        mSaveStateSeq++;
+        if (mActive == null || mActive.size() <= 0) {
+            return null;
+        }
         
-        if (mFragments == null) {
+        // First collect all active fragments.
+        int N = mActive.size();
+        FragmentState[] active = new FragmentState[N];
+        boolean haveFragments = false;
+        for (int i=0; i<N; i++) {
+            Fragment f = mActive.get(i);
+            if (f != null) {
+                haveFragments = true;
+                
+                FragmentState fs = new FragmentState(f);
+                active[i] = fs;
+                
+                if (mStateBundle == null) {
+                    mStateBundle = new Bundle();
+                }
+                f.onSaveInstanceState(mStateBundle);
+                if (!mStateBundle.isEmpty()) {
+                    fs.mSavedFragmentState = mStateBundle;
+                    mStateBundle = null;
+                }
+                
+                if (f.mView != null) {
+                    saveFragmentViewState(f);
+                    if (f.mSavedViewState != null) {
+                        if (fs.mSavedFragmentState == null) {
+                            fs.mSavedFragmentState = new Bundle();
+                        }
+                        fs.mSavedFragmentState.putSparseParcelableArray(
+                                FragmentState.VIEW_STATE_TAG, f.mSavedViewState);
+                    }
+                }
+                
+            }
+        }
+        
+        if (!haveFragments) {
             return null;
         }
         
         int[] added = null;
         BackStackState[] backStack = null;
         
-        // First collect all active fragments.
-        int N = mFragments.size();
+        // Build list of currently added fragments.
+        N = mAdded.size();
         if (N > 0) {
             added = new int[N];
             for (int i=0; i<N; i++) {
-                added[i] = saveFragment(mFragments.get(i)).mSavedStateId;
+                added[i] = mAdded.get(i).mIndex;
             }
         }
         
@@ -704,21 +767,8 @@
             }
         }
         
-        if (mSavedFragments == null) {
-            return null;
-        }
-        N = mSavedFragments.size();
-        if (N <= 0) {
-            return null;
-        }
-        
         FragmentManagerState fms = new FragmentManagerState();
-        fms.mFragments = new FragmentState[N];
-        int i = 0;
-        for (FragmentState fs : mSavedFragments.values()) {
-            fms.mFragments[i] = fs;
-            i++;
-        }
+        fms.mActive = active;
         fms.mAdded = added;
         fms.mBackStack = backStack;
         return fms;
@@ -729,54 +779,69 @@
         // any nonConfig fragments either, so that is that.
         if (state == null) return;
         FragmentManagerState fms = (FragmentManagerState)state;
-        if (fms.mFragments == null) return;
+        if (fms.mActive == null) return;
         
-        // First build our lookup table of all known Fragment objects.
-        mRestoredFragments = new SparseArray<FragmentState>();
-        for (int i=0; i<fms.mFragments.length; i++) {
-            FragmentState fs = fms.mFragments[i];
-            mRestoredFragments.put(fs.mSavedStateId, fs);
-        }
-        
-        // Stick any non-config instances we are retaining directly
-        // into the lookup table, so we don't try to instantiate them again.
+        // First re-attach any non-config instances we are retaining back
+        // to their saved state, so we don't try to instantiate them again.
         if (nonConfig != null) {
             for (int i=0; i<nonConfig.size(); i++) {
                 Fragment f = nonConfig.get(i);
-                FragmentState fs = mRestoredFragments.get(f.mSavedStateId);
+                FragmentState fs = fms.mActive[f.mIndex];
                 fs.mInstance = f;
                 f.mSavedViewState = null;
+                f.mBackStackNesting = 0;
+                f.mAdded = false;
                 if (fs.mSavedFragmentState != null) {
                     f.mSavedViewState = fs.mSavedFragmentState.getSparseParcelableArray(
                             FragmentState.VIEW_STATE_TAG);
                 }
-                addFragment(f, false);
             }
         }
         
-        // Now build our data structures from the saved state, instantiating
-        // the fragment objects as needed.
-        if (fms.mAdded != null) {
-            if (mFragments == null) {
-                mFragments = new ArrayList<Fragment>(fms.mAdded.length);
-            }
-            for (int i=0; i<fms.mAdded.length; i++) {
-                FragmentState fs = mRestoredFragments.get(fms.mAdded[i]);
-                Fragment f = fs.instantiate(mActivity);
-                // This will return null if this is a layout fragment,
-                // since the instance for such a fragment will be created
-                // later during layout inflation.
-                if (f != null) {
-                    mFragments.add(f);
+        // Build the full list of active fragments, instantiating them from
+        // their saved state.
+        mActive = new ArrayList<Fragment>(fms.mActive.length);
+        if (mAvailIndices != null) {
+            mAvailIndices.clear();
+        }
+        for (int i=0; i<fms.mActive.length; i++) {
+            FragmentState fs = fms.mActive[i];
+            if (fs != null) {
+                mActive.add(fs.instantiate(mActivity));
+            } else {
+                mActive.add(null);
+                if (mAvailIndices == null) {
+                    mAvailIndices = new ArrayList<Integer>();
                 }
+                mAvailIndices.add(i);
             }
         }
+        
+        // Build the list of currently added fragments.
+        if (fms.mAdded != null) {
+            mAdded = new ArrayList<Fragment>(fms.mAdded.length);
+            for (int i=0; i<fms.mAdded.length; i++) {
+                Fragment f = mActive.get(fms.mAdded[i]);
+                if (f == null) {
+                    throw new IllegalStateException(
+                            "No instantiated fragment for index #" + fms.mAdded[i]);
+                }
+                f.mAdded = true;
+                mAdded.add(f);
+            }
+        } else {
+            mAdded = null;
+        }
+        
+        // Build the back stack.
         if (fms.mBackStack != null) {
             mBackStack = new ArrayList<BackStackEntry>(fms.mBackStack.length);
             for (int i=0; i<fms.mBackStack.length; i++) {
                 BackStackEntry bse = fms.mBackStack[i].instantiate(this);
                 mBackStack.add(bse);
             }
+        } else {
+            mBackStack = null;
         }
     }
     
@@ -802,7 +867,7 @@
     }
     
     public void dispatchStop() {
-        moveToState(Fragment.CREATED, false);
+        moveToState(Fragment.CONTENT, false);
     }
     
     public void dispatchDestroy() {
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index cbb1c1a..4d5f36a 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1335,7 +1335,7 @@
      *                      is being started.
      * @param token Internal token identifying to the system who is starting 
      *              the activity; may be null.
-     * @param target Which activity is perform the start (and thus receiving 
+     * @param target Which activity is performing the start (and thus receiving 
      *               any result); may be null if this call is not being made
      *               from an activity.
      * @param intent The actual Intent to start.
@@ -1385,6 +1385,64 @@
         return null;
     }
 
+    /**
+     * Like {@link #execStartActivity(Context, IBinder, IBinder, Activity, Intent, int)},
+     * but for calls from a {#link Fragment}.
+     * 
+     * @param who The Context from which the activity is being started.
+     * @param contextThread The main thread of the Context from which the activity
+     *                      is being started.
+     * @param token Internal token identifying to the system who is starting 
+     *              the activity; may be null.
+     * @param target Which fragment is performing the start (and thus receiving 
+     *               any result).
+     * @param intent The actual Intent to start.
+     * @param requestCode Identifier for this request's result; less than zero 
+     *                    if the caller is not expecting a result.
+     * 
+     * @return To force the return of a particular result, return an 
+     *         ActivityResult object containing the desired data; otherwise
+     *         return null.  The default implementation always returns null.
+     *  
+     * @throws android.content.ActivityNotFoundException
+     * 
+     * @see Activity#startActivity(Intent)
+     * @see Activity#startActivityForResult(Intent, int)
+     * @see Activity#startActivityFromChild
+     * 
+     * {@hide}
+     */
+    public ActivityResult execStartActivity(
+        Context who, IBinder contextThread, IBinder token, Fragment target,
+        Intent intent, int requestCode) {
+        IApplicationThread whoThread = (IApplicationThread) contextThread;
+        if (mActivityMonitors != null) {
+            synchronized (mSync) {
+                final int N = mActivityMonitors.size();
+                for (int i=0; i<N; i++) {
+                    final ActivityMonitor am = mActivityMonitors.get(i);
+                    if (am.match(who, null, intent)) {
+                        am.mHits++;
+                        if (am.isBlocking()) {
+                            return requestCode >= 0 ? am.getResult() : null;
+                        }
+                        break;
+                    }
+                }
+            }
+        }
+        try {
+            int result = ActivityManagerNative.getDefault()
+                .startActivity(whoThread, intent,
+                        intent.resolveTypeIfNeeded(who.getContentResolver()),
+                        null, 0, token, target != null ? target.mWho : null,
+                        requestCode, false, false);
+            checkStartActivityResult(result, intent);
+        } catch (RemoteException e) {
+        }
+        return null;
+    }
+
     /*package*/ final void init(ActivityThread thread,
             Context instrContext, Context appContext, ComponentName component, 
             IInstrumentationWatcher watcher) {