Clean up open/close state for DragLayout.

Fixes: 33105843

-Remove onClose() from DragCallback and introduce CloseCallback.
-Call executePendingTransactions() when popping fragment backstack.
-Rename "onStartDragging()" to "onStartDraggingOpen()" and only call
it eponymously

Change-Id: I4fc30788a7fe3fa017ba051f48941163b3e04079
diff --git a/src/com/android/calculator2/Calculator.java b/src/com/android/calculator2/Calculator.java
index fa7aa42..b877ed6 100644
--- a/src/com/android/calculator2/Calculator.java
+++ b/src/com/android/calculator2/Calculator.java
@@ -87,6 +87,7 @@
         implements OnTextSizeChangeListener, OnLongClickListener,
         AlertDialogFragment.OnClickListener, Evaluator.EvaluationListener /* for main result */ {
 
+    private static final String TAG = "Calculator";
     /**
      * Constant for an invalid resource id.
      */
@@ -221,9 +222,16 @@
         }
     };
 
+    private final DragLayout.CloseCallback mCloseCallback = new DragLayout.CloseCallback() {
+        @Override
+        public void onClose() {
+            popFragmentBackstack();
+        }
+    };
+
     private final DragLayout.DragCallback mDragCallback = new DragLayout.DragCallback() {
         @Override
-        public void onStartDragging() {
+        public void onStartDraggingOpen() {
             showHistoryFragment(FragmentTransaction.TRANSIT_NONE);
         }
 
@@ -233,11 +241,6 @@
         }
 
         @Override
-        public void onClosed() {
-            popFragmentBackstack();
-        }
-
-        @Override
         public boolean allowDrag(MotionEvent event) {
             return isViewTarget(mHistoryFrame, event) || isViewTarget(mDisplayView, event);
         }
@@ -414,6 +417,7 @@
         mDragLayout = (DragLayout) findViewById(R.id.drag_layout);
         mDragLayout.removeDragCallback(mDragCallback);
         mDragLayout.addDragCallback(mDragCallback);
+        mDragLayout.setCloseCallback(mCloseCallback);
 
         mHistoryFrame = (FrameLayout) findViewById(R.id.history_frame);
 
@@ -701,7 +705,9 @@
             return;
         }
         manager.popBackStack();
+        manager.executePendingTransactions();
     }
+
     /**
      * Switch to INPUT from RESULT state in response to input of the specified button_id.
      * View.NO_ID is treated as an incomplete function id.
diff --git a/src/com/android/calculator2/DragLayout.java b/src/com/android/calculator2/DragLayout.java
index e7920ce..b07d087 100644
--- a/src/com/android/calculator2/DragLayout.java
+++ b/src/com/android/calculator2/DragLayout.java
@@ -41,6 +41,7 @@
     private ViewDragHelper mDragHelper;
 
     private final List<DragCallback> mDragCallbacks = new ArrayList<>();
+    private CloseCallback mCloseCallback;
 
     private int mDraggingState = ViewDragHelper.STATE_IDLE;
     private int mDraggingBorder;
@@ -158,7 +159,7 @@
 
     private void onStartDragging() {
         for (DragCallback c : mDragCallbacks) {
-            c.onStartDragging();
+            c.onStartDraggingOpen();
         }
         mHistoryFrame.setVisibility(VISIBLE);
     }
@@ -174,17 +175,15 @@
 
     public void setOpen() {
         mDragHelper.smoothSlideViewTo(mHistoryFrame, 0, mVerticalRange);
-        mIsOpen = true;
         mHistoryFrame.setVisibility(VISIBLE);
     }
 
     public void setClosed() {
-        // Scroll the RecyclerView to the bottom.
-        for (DragCallback c : mDragCallbacks) {
-            c.onClosed();
-        }
         mDragHelper.smoothSlideViewTo(mHistoryFrame, 0, 0);
-        mIsOpen = false;
+    }
+
+    public void setCloseCallback(CloseCallback callback) {
+        mCloseCallback = callback;
     }
 
     public void addDragCallback(DragCallback callback) {
@@ -196,18 +195,26 @@
     }
 
     /**
+     * Callback when the layout is closed.
+     * We use this to pop the HistoryFragment off the backstack.
+     * We can't use a method in DragCallback because we get ConcurrentModificationExceptions on
+     * mDragCallbacks when executePendingTransactions() is called for popping the fragment off the
+     * backstack.
+     */
+    public interface CloseCallback {
+        void onClose();
+    }
+
+    /**
      * Callbacks for coordinating with the RecyclerView or HistoryFragment.
      */
     public interface DragCallback {
-        // Callback when a drag in any direction begins.
-        void onStartDragging();
+        // Callback when a drag to open begins.
+        void onStartDraggingOpen();
 
         // Animate the RecyclerView text.
         void whileDragging(float yFraction);
 
-        // Scroll the RecyclerView to the bottom before closing the frame.
-        void onClosed();
-
         // Whether we should allow the drag to happen
         boolean allowDrag(MotionEvent event);
 
@@ -232,12 +239,16 @@
                 // The view stopped moving.
                 if (mDraggingBorder == 0) {
                     setClosed();
+                    mIsOpen = false;
                     mHistoryFrame.setVisibility(GONE);
+                    if (mCloseCallback != null) {
+                        mCloseCallback.onClose();
+                    }
                 } else if (mDraggingBorder == mVerticalRange) {
                     setOpen();
+                    mIsOpen = true;
                 }
-            }
-            if (state == ViewDragHelper.STATE_DRAGGING) {
+            } else if (state == ViewDragHelper.STATE_DRAGGING && !mIsOpen) {
                 onStartDragging();
             }
             mDraggingState = state;
diff --git a/src/com/android/calculator2/HistoryFragment.java b/src/com/android/calculator2/HistoryFragment.java
index bfc7273..22adcd3 100644
--- a/src/com/android/calculator2/HistoryFragment.java
+++ b/src/com/android/calculator2/HistoryFragment.java
@@ -38,7 +38,7 @@
     private final DragLayout.DragCallback mDragCallback =
             new DragLayout.DragCallback() {
                 @Override
-                public void onStartDragging() {
+                public void onStartDraggingOpen() {
                     // no-op
                 }
 
@@ -48,11 +48,6 @@
                 }
 
                 @Override
-                public void onClosed() {
-                    mEvaluator.cancelNonMain();
-                }
-
-                @Override
                 public boolean allowDrag(MotionEvent event) {
                     // Do not allow drag if the recycler view can move down more
                     return !mRecyclerView.canScrollVertically(1);
@@ -200,8 +195,11 @@
             dragLayout.removeDragCallback(mDragCallback);
         }
 
+        // Note that the view is destroyed when the fragment backstack is popped, so
+        // these are essentially called when the DragLayout is closed.
         mEvaluator.cancelNonMain();
-        super.onDestroy();
+
+        super.onDestroyView();
     }
 
     private void initializeController(boolean isResult) {