Don't commit transactions after onSaveInstanceState()

- On the tablet portrait view, once the contact details are loaded,
a runnable is posted to a handler to properly setup the fragments
(by showing/hiding the ContactDetailFragment or ViewPager/Tab carousel)
- Since it's posted to a handler, we need to make sure that
onSaveInstanceState has not already been called or at least allow
the fragment transaction to be lost if it has been
- Prevent the runnable from doing anything if the activity is already
destroyed

Bug: 5011890

Change-Id: Ib43278f21eee390202ffe4b7ed4057482c34e61c
diff --git a/src/com/android/contacts/activities/PeopleActivity.java b/src/com/android/contacts/activities/PeopleActivity.java
index 6d031e9..579c833 100644
--- a/src/com/android/contacts/activities/PeopleActivity.java
+++ b/src/com/android/contacts/activities/PeopleActivity.java
@@ -180,6 +180,14 @@
      */
     private boolean mFragmentInitialized;
 
+    /**
+     * Whether or not the activity is destroyed. This flag is needed to ensure that the
+     * {@link Handler} does not execute any {@link FragmentTransaction}s in {@link Runnable}s
+     * after the activity is destroyed.
+     * TODO: Figure out a way to get rid of the {@link Handler} or make the operation safe.
+     */
+    private boolean mIsActivityDestroyed = false;
+
     /** Sequential ID assigned to each instance; used for logging */
     private final int mInstanceId;
     private static final AtomicInteger sNextInstanceId = new AtomicInteger();
@@ -463,6 +471,7 @@
 
     @Override
     protected void onDestroy() {
+        mIsActivityDestroyed = true;
         // mActionBarAdapter will be null here when redirecting to another activity in
         // configureContentView().
         if (mActionBarAdapter != null) {
@@ -1005,6 +1014,10 @@
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
+                    // Don't continue setting up the detail page if the activity is destroyed.
+                    if (mIsActivityDestroyed) {
+                        return;
+                    }
                     if (!mContactDetailLayoutController.isInitialized()) {
                         mContactDetailLayoutController.setContactDetailFragment(
                                 mContactDetailFragment);
diff --git a/src/com/android/contacts/detail/ContactDetailLayoutController.java b/src/com/android/contacts/detail/ContactDetailLayoutController.java
index 826d720..dda3884 100644
--- a/src/com/android/contacts/detail/ContactDetailLayoutController.java
+++ b/src/com/android/contacts/detail/ContactDetailLayoutController.java
@@ -161,7 +161,12 @@
                 throw new IllegalStateException("Invalid LayoutMode " + mLayoutMode);
         }
 
-        ft.commit();
+        // If the activity has already saved its state, then allow this fragment
+        // transaction to be dropped because there's nothing else we can do to update the UI.
+        // The fact that the contact URI has already been saved by the activity means we can
+        // restore this later.
+        // TODO: Figure out if this is really the solution we want.
+        ft.commitAllowingStateLoss();
     }
 
     private void showContactWithoutUpdates() {
@@ -182,7 +187,12 @@
                 throw new IllegalStateException("Invalid LayoutMode " + mLayoutMode);
         }
 
-        ft.commit();
+        // If the activity has already saved its state, then allow this fragment
+        // transaction to be dropped because there's nothing else we can do to update the UI.
+        // The fact that the contact URI has already been saved by the activity means we can
+        // restore this later.
+        // TODO: Figure out if this is really the solution we want.
+        ft.commitAllowingStateLoss();
     }
 
     public void onSaveInstanceState(Bundle outState) {