Don't re-use mHistoryFragment

Make a new HistoryFragment every time we enter and exit history to work
around a bug on older platforms where a Fragment's internal state may
not be reset correctly when detached.

Also the HistoryFragment open/close transition is now properly animated
using a custom Animator returned by DragLayout.

Fixes: 33587141
Fixes: 33789131
Fixes: 33789337
Fixes: 34132294
Fixes: 34132998
Fixes: 34134349
Fixes: 34135442

Test: manually verified no crash occurs on API 22, 23, & 24 emulator
Change-Id: Iaefbe2bbf4ca186b6396397579887774ed5906d3
diff --git a/src/com/android/calculator2/Calculator.java b/src/com/android/calculator2/Calculator.java
index 970683b..5019fdf 100644
--- a/src/com/android/calculator2/Calculator.java
+++ b/src/com/android/calculator2/Calculator.java
@@ -34,6 +34,7 @@
 import android.app.ActionBar;
 import android.app.Activity;
 import android.app.FragmentManager;
+import android.app.FragmentTransaction;
 import android.content.ClipData;
 import android.content.DialogInterface;
 import android.content.Intent;
@@ -66,7 +67,6 @@
 import android.view.ViewGroupOverlay;
 import android.view.ViewTreeObserver;
 import android.view.animation.AccelerateDecelerateInterpolator;
-import android.widget.FrameLayout;
 import android.widget.HorizontalScrollView;
 import android.widget.TextView;
 import android.widget.Toolbar;
@@ -252,7 +252,6 @@
     private CalculatorResult mResultText;
     private HorizontalScrollView mFormulaContainer;
     private DragLayout mDragLayout;
-    private FrameLayout mHistoryFrame;
 
     private ViewPager mPadViewPager;
     private View mDeleteButton;
@@ -280,8 +279,6 @@
     // Whether the display is one line.
     private boolean mIsOneLine;
 
-    private HistoryFragment mHistoryFragment = new HistoryFragment();
-
     /**
      * Map the old saved state to a new state reflecting requested result reevaluation.
      */
@@ -421,8 +418,6 @@
         mDragLayout.addDragCallback(this);
         mDragLayout.setCloseCallback(this);
 
-        mHistoryFrame = (FrameLayout) findViewById(R.id.history_frame);
-
         mFormulaText.setOnContextMenuClickListener(mOnFormulaContextMenuClickListener);
         mFormulaText.setOnDisplayMemoryOperationsListener(mOnDisplayMemoryOperationsListener);
 
@@ -596,8 +591,10 @@
     public boolean dispatchTouchEvent(MotionEvent e) {
         if (e.getActionMasked() == MotionEvent.ACTION_DOWN) {
             stopActionModeOrContextMenu();
-            if (mDragLayout.isOpen()) {
-                mHistoryFragment.stopActionModeOrContextMenu();
+
+            final HistoryFragment historyFragment = getHistoryFragment();
+            if (mDragLayout.isOpen() && historyFragment != null) {
+                historyFragment.stopActionModeOrContextMenu();
             }
         }
         return super.dispatchTouchEvent(e);
@@ -606,9 +603,9 @@
     @Override
     public void onBackPressed() {
         if (!stopActionModeOrContextMenu()) {
-            if (mDragLayout.isOpen()) {
-                if (!mHistoryFragment.stopActionModeOrContextMenu()) {
-                    mDragLayout.setClosed();
+            final HistoryFragment historyFragment = getHistoryFragment();
+            if (mDragLayout.isOpen() && historyFragment != null) {
+                if (!historyFragment.stopActionModeOrContextMenu()) {
                     removeHistoryFragment();
                 }
                 return;
@@ -1278,8 +1275,7 @@
     public boolean onOptionsItemSelected(MenuItem item) {
         switch (item.getItemId()) {
             case R.id.menu_history:
-                showHistoryFragment();
-                mDragLayout.setOpen();
+                showHistoryFragment(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
                 return true;
             case R.id.menu_leading:
                 displayFull();
@@ -1306,21 +1302,23 @@
 
     /* Begin override DragCallback methods */
 
-    @Override
     public void onStartDraggingOpen() {
-        showHistoryFragment();
+        mDisplayView.hideToolbar();
+        showHistoryFragment(FragmentTransaction.TRANSIT_NONE);
+    }
+
+    @Override
+    public void onInstanceStateRestored(boolean isOpen) {
     }
 
     @Override
     public void whileDragging(float yFraction) {
-        // no-op
     }
 
     @Override
     public boolean shouldCaptureView(View view, int x, int y) {
-        return mDragLayout.isMoving()
-                || mDragLayout.isOpen()
-                || mDragLayout.isViewUnder(mDisplayView, x, y);
+        return view.getId() == R.id.history_frame
+            && (mDragLayout.isMoving() || mDragLayout.isViewUnder(view, x, y));
     }
 
     @Override
@@ -1328,11 +1326,6 @@
         return mDisplayView.getMeasuredHeight();
     }
 
-    @Override
-    public void onLayout(int translation) {
-        mHistoryFrame.setTranslationY(translation + mDisplayView.getBottom());
-    }
-
     /* End override DragCallback methods */
 
     /**
@@ -1358,27 +1351,34 @@
         return true;
     }
 
-    private void showHistoryFragment() {
+    private HistoryFragment getHistoryFragment() {
+        final FragmentManager manager = getFragmentManager();
+        if (manager == null || manager.isDestroyed()) {
+            return null;
+        }
+        return (HistoryFragment) manager.findFragmentByTag(HistoryFragment.TAG);
+    }
+
+    private void showHistoryFragment(int transit) {
         final FragmentManager manager = getFragmentManager();
         if (manager == null || manager.isDestroyed()) {
             return;
         }
-        if (!prepareForHistory()) {
+
+        if (getHistoryFragment() != null || !prepareForHistory()) {
             return;
         }
-        if (!mDragLayout.isOpen()) {
-            stopActionModeOrContextMenu();
 
-            manager.beginTransaction()
-                    .replace(R.id.history_frame, mHistoryFragment, HistoryFragment.TAG)
-                    .addToBackStack(HistoryFragment.TAG)
-                    .commit();
-            manager.executePendingTransactions();
+        stopActionModeOrContextMenu();
+        manager.beginTransaction()
+                .replace(R.id.history_frame, new HistoryFragment(), HistoryFragment.TAG)
+                .setTransition(transit)
+                .addToBackStack(HistoryFragment.TAG)
+                .commit();
 
-            // When HistoryFragment is visible, hide all descendants of the main Calculator view.
-            mMainCalculator.setImportantForAccessibility(
-                    View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
-        }
+        // When HistoryFragment is visible, hide all descendants of the main Calculator view.
+        mMainCalculator.setImportantForAccessibility(
+                View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
         // TODO: pass current scroll position of result
     }