Merge "Fix getting wrong instance when restoring non-config" into nyc-support-25.4-dev
diff --git a/fragment/java/android/support/v4/app/FragmentManager.java b/fragment/java/android/support/v4/app/FragmentManager.java
index 48e6698..e071de2 100644
--- a/fragment/java/android/support/v4/app/FragmentManager.java
+++ b/fragment/java/android/support/v4/app/FragmentManager.java
@@ -2806,7 +2806,15 @@
             for (int i = 0; i < count; i++) {
                 Fragment f = nonConfigFragments.get(i);
                 if (DEBUG) Log.v(TAG, "restoreAllState: re-attaching retained " + f);
-                FragmentState fs = fms.mActive[f.mIndex];
+                int index = 0; // index into fms.mActive
+                while (index < fms.mActive.length && fms.mActive[index].mIndex != f.mIndex) {
+                    index++;
+                }
+                if (index == fms.mActive.length) {
+                    throwException(new IllegalStateException("Could not find active fragment "
+                            + "with index " + f.mIndex));
+                }
+                FragmentState fs = fms.mActive[index];
                 fs.mInstance = f;
                 f.mSavedViewState = null;
                 f.mBackStackNesting = 0;
diff --git a/fragment/tests/java/android/support/v4/app/FragmentLifecycleTest.java b/fragment/tests/java/android/support/v4/app/FragmentLifecycleTest.java
index c9d7351..c6db19b 100644
--- a/fragment/tests/java/android/support/v4/app/FragmentLifecycleTest.java
+++ b/fragment/tests/java/android/support/v4/app/FragmentLifecycleTest.java
@@ -684,6 +684,52 @@
         assertTrue(activity.onDestroyLatch.await(1000, TimeUnit.MILLISECONDS));
     }
 
+    /**
+     * When a fragment is saved in non-config, it should be restored to the same index.
+     */
+    @Test
+    @UiThreadTest
+    public void restoreNonConfig() throws Throwable {
+        FragmentController fc = FragmentTestUtil.createController(mActivityRule);
+        FragmentTestUtil.resume(mActivityRule, fc, null);
+        FragmentManager fm = fc.getSupportFragmentManager();
+
+        Fragment fragment1 = new StrictFragment();
+        fm.beginTransaction()
+                .add(fragment1, "1")
+                .addToBackStack(null)
+                .commit();
+        fm.executePendingTransactions();
+        Fragment fragment2 = new StrictFragment();
+        fragment2.setRetainInstance(true);
+        fragment2.setTargetFragment(fragment1, 0);
+        Fragment fragment3 = new StrictFragment();
+        fm.beginTransaction()
+                .remove(fragment1)
+                .add(fragment2, "2")
+                .add(fragment3, "3")
+                .addToBackStack(null)
+                .commit();
+        fm.executePendingTransactions();
+
+        Pair<Parcelable, FragmentManagerNonConfig> savedState =
+                FragmentTestUtil.destroy(mActivityRule, fc);
+
+        fc = FragmentTestUtil.createController(mActivityRule);
+        FragmentTestUtil.resume(mActivityRule, fc, savedState);
+        boolean foundFragment2 = false;
+        for (Fragment fragment : fc.getSupportFragmentManager().getFragments()) {
+            if (fragment == fragment2) {
+                foundFragment2 = true;
+                assertNotNull(fragment.getTargetFragment());
+                assertEquals("1", fragment.getTargetFragment().getTag());
+            } else {
+                assertNotEquals("2", fragment.getTag());
+            }
+        }
+        assertTrue(foundFragment2);
+    }
+
     private void assertAnimationsMatch(FragmentManager fm, int enter, int exit, int popEnter,
             int popExit) {
         FragmentManagerImpl fmImpl = (FragmentManagerImpl) fm;
diff --git a/fragment/tests/java/android/support/v4/app/FragmentTestUtil.java b/fragment/tests/java/android/support/v4/app/FragmentTestUtil.java
index ff48420..9ee0c48 100644
--- a/fragment/tests/java/android/support/v4/app/FragmentTestUtil.java
+++ b/fragment/tests/java/android/support/v4/app/FragmentTestUtil.java
@@ -145,9 +145,10 @@
         }
     }
 
-    public static FragmentController createController(ActivityTestRule<FragmentTestActivity> rule) {
+    public static FragmentController createController(
+            ActivityTestRule<? extends FragmentActivity> rule) {
         final FragmentController[] controller = new FragmentController[1];
-        final FragmentTestActivity activity = rule.getActivity();
+        final FragmentActivity activity = rule.getActivity();
         runOnUiThreadRethrow(rule, new Runnable() {
             @Override
             public void run() {
diff --git a/fragment/tests/java/android/support/v4/app/HostCallbacks.java b/fragment/tests/java/android/support/v4/app/HostCallbacks.java
index 9a0ef1c..15698a6 100644
--- a/fragment/tests/java/android/support/v4/app/HostCallbacks.java
+++ b/fragment/tests/java/android/support/v4/app/HostCallbacks.java
@@ -16,20 +16,19 @@
 package android.support.v4.app;
 
 import android.os.Handler;
-import android.support.v4.app.test.FragmentTestActivity;
 import android.view.LayoutInflater;
 import android.view.View;
 
-class HostCallbacks extends FragmentHostCallback<FragmentTestActivity> {
-    private final FragmentTestActivity mActivity;
+class HostCallbacks extends FragmentHostCallback<FragmentActivity> {
+    private final FragmentActivity mActivity;
 
-    HostCallbacks(FragmentTestActivity activity, Handler handler, int windowAnimations) {
+    HostCallbacks(FragmentActivity activity, Handler handler, int windowAnimations) {
         super(activity, handler, windowAnimations);
         mActivity = activity;
     }
 
     @Override
-    public FragmentTestActivity onGetHost() {
+    public FragmentActivity onGetHost() {
         return mActivity;
     }