DO NOT MERGE Re-use existing group and duplicates fragments if possible

- If group fragment is added and visible and we are loading another
  group, we simply update the existing group fragment.
- Always see if a fragment is in fargment manager before creating and
  adding another one.
- Scroll to top when switching to all contacts view.
- Address a TODO to pop group fragment rather than finishing activity.

Bug: 30944495

Test: manual - navigate b/w fragments (w/ rotation), add and remove
               groups; and observe fragment manager's behavior.

Change-Id: Idff71e62ed6ff6e2a12884b2f232336fe3edbf38
(cherry picked from commit febd4a7508b0c33d6dc3da10c8792d3c4f6b665d)
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index d5add16..b2a0a07 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -387,10 +387,7 @@
 
         setUpAllFragment(fragmentManager);
 
-        if (isGroupView()) {
-            mMembersFragment = (GroupMembersFragment)
-                    fragmentManager.findFragmentByTag(TAG_GROUP_VIEW);
-        }
+        mMembersFragment = (GroupMembersFragment) fragmentManager.findFragmentByTag(TAG_GROUP_VIEW);
 
         // Configure floating action button
         mFloatingActionButtonContainer = findViewById(R.id.floating_action_button_container);
@@ -763,10 +760,11 @@
     }
 
     private void switchToOrUpdateGroupView(String action) {
-        final boolean shouldUpdate = mMembersFragment != null;
-        switchView(ContactsView.GROUP_VIEW);
-        if (shouldUpdate) {
+        // If group fragment is active and visible, we simply update it.
+        if (mMembersFragment != null && !mMembersFragment.isInactive()) {
             mMembersFragment.updateExistingGroupFragment(mGroupUri, action);
+        } else {
+            switchView(ContactsView.GROUP_VIEW);
         }
     }
 
@@ -787,15 +785,21 @@
             transaction.replace(
                     R.id.contacts_list_container, mMembersFragment, TAG_GROUP_VIEW);
         } else if (isDuplicatesView()) {
-            final Fragment duplicatesFragment = ObjectFactory.getDuplicatesFragment();
-            final Fragment duplicatesUtilFragment = ObjectFactory.getDuplicatesUtilFragment();
-            if (duplicatesFragment != null && duplicatesUtilFragment != null) {
+            Fragment duplicatesFragment = fragmentManager.findFragmentByTag(TAG_DUPLICATES);
+            Fragment duplicatesUtilFragment =
+                    fragmentManager.findFragmentByTag(TAG_DUPLICATES_UTIL);
+            if (duplicatesFragment == null || duplicatesUtilFragment == null) {
+                duplicatesFragment = ObjectFactory.getDuplicatesFragment();
+                duplicatesUtilFragment = ObjectFactory.getDuplicatesUtilFragment();
                 duplicatesUtilFragment.setTargetFragment(duplicatesFragment, /* requestCode */ 0);
-                transaction.replace(
-                        R.id.contacts_list_container, duplicatesFragment, TAG_DUPLICATES);
+            }
+            transaction.replace(
+                    R.id.contacts_list_container, duplicatesFragment, TAG_DUPLICATES);
+            if (!duplicatesUtilFragment.isAdded()) {
                 transaction.add(duplicatesUtilFragment, TAG_DUPLICATES_UTIL);
                 resetToolBarStatusBarColor();
             }
+            resetToolBarStatusBarColor();
         }
         transaction.addToBackStack(TAG_SECOND_LEVEL);
         transaction.commit();
@@ -812,6 +816,7 @@
         mShouldSwitchToAllContacts = false;
         mCurrentView = ContactsView.ALL_CONTACTS;
         showFabWithAnimation(/* showFab */ true);
+        mAllFragment.scrollToTop();
 
         super.switchToAllContacts();
     }
diff --git a/src/com/android/contacts/group/GroupMembersFragment.java b/src/com/android/contacts/group/GroupMembersFragment.java
index 809cf20..30f339c 100644
--- a/src/com/android/contacts/group/GroupMembersFragment.java
+++ b/src/com/android/contacts/group/GroupMembersFragment.java
@@ -24,8 +24,9 @@
 import android.database.CursorWrapper;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
 import android.provider.ContactsContract.Contacts;
-import android.support.v7.app.AppCompatActivity;
 import android.util.Log;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -78,7 +79,7 @@
     private static final String ARG_GROUP_URI = "groupUri";
 
     private static final int LOADER_GROUP_METADATA = 0;
-
+    private static final int MSG_FAIL_TO_LOAD = 1;
     private static final int RESULT_GROUP_ADD_MEMBER = 100;
 
     /** Filters out duplicate contacts. */
@@ -194,9 +195,7 @@
                 Log.e(TAG, "Failed to load group metadata for " + mGroupUri);
                 Toast.makeText(getContext(), R.string.groupLoadErrorToast, Toast.LENGTH_SHORT)
                         .show();
-                // TODO: we probably shouldn't finish mActivity.
-                mActivity.setResult(AppCompatActivity.RESULT_CANCELED);
-                mActivity.finish();
+                mHandler.sendEmptyMessage(MSG_FAIL_TO_LOAD);
                 return;
             }
             mGroupMetaData = new GroupMetaData(getActivity(), cursor);
@@ -219,6 +218,15 @@
 
     private Set<String> mGroupMemberContactIds = new HashSet();
 
+    private Handler mHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            if(msg.what == MSG_FAIL_TO_LOAD) {
+                mActivity.onBackPressed();
+            }
+        }
+    };
+
     public static GroupMembersFragment newInstance(Uri groupUri) {
         final Bundle args = new Bundle();
         args.putParcelable(ARG_GROUP_URI, groupUri);
@@ -646,6 +654,13 @@
         return mGroupMetaData != null && mGroupMetaData.groupId == groupId;
     }
 
+    /**
+     * Return true if the fragment is not yet added, being removed, or detached.
+     */
+    public boolean isInactive() {
+        return !isAdded() || isRemoving() || isDetached();
+    }
+
     @Override
     public void onDestroy() {
         if (mActionBarAdapter != null) {