Merge "Refuse to open history if in ANIMATE state." into pi-dev
diff --git a/src/com/android/calculator2/Calculator.java b/src/com/android/calculator2/Calculator.java
index 392447c..81ab1f6 100644
--- a/src/com/android/calculator2/Calculator.java
+++ b/src/com/android/calculator2/Calculator.java
@@ -535,9 +535,6 @@
     }
 
     public boolean isResultLayout() {
-        if (mCurrentState == CalculatorState.ANIMATE) {
-            throw new AssertionError("impossible state");
-        }
         // Note that ERROR has INPUT, not RESULT layout.
         return mCurrentState == CalculatorState.INIT_FOR_RESULT
                 || mCurrentState == CalculatorState.RESULT;
@@ -1339,7 +1336,14 @@
      */
     private boolean prepareForHistory() {
         if (mCurrentState == CalculatorState.ANIMATE) {
-            throw new AssertionError("onUserInteraction should have ended animation");
+            // End the current animation and signal that preparation has failed.
+            // onUserInteraction is unreliable and onAnimationEnd() is asynchronous, so we
+            // aren't guaranteed to be out of the ANIMATE state by the time prepareForHistory is
+            // called.
+            if (mCurrentAnimator != null) {
+                mCurrentAnimator.end();
+            }
+            return false;
         } else if (mCurrentState == CalculatorState.EVALUATE) {
             // Cancel current evaluation
             cancelIfEvaluating(true /* quiet */ );
@@ -1366,12 +1370,15 @@
     }
 
     private void showHistoryFragment() {
-        final FragmentManager manager = getFragmentManager();
-        if (manager == null || manager.isDestroyed()) {
+        if (getHistoryFragment() != null) {
+            // If the fragment already exists, do nothing.
             return;
         }
 
-        if (getHistoryFragment() != null || !prepareForHistory()) {
+        final FragmentManager manager = getFragmentManager();
+        if (manager == null || manager.isDestroyed() || !prepareForHistory()) {
+            // If the history fragment can not be shown, close the draglayout.
+            mDragLayout.setClosed();
             return;
         }
 
diff --git a/src/com/android/calculator2/DragLayout.java b/src/com/android/calculator2/DragLayout.java
index e34c4da..74b0a8e 100644
--- a/src/com/android/calculator2/DragLayout.java
+++ b/src/com/android/calculator2/DragLayout.java
@@ -209,14 +209,11 @@
         return mIsOpen;
     }
 
-    private void setClosed() {
-        if (mIsOpen) {
-            mIsOpen = false;
-            mHistoryFrame.setVisibility(View.INVISIBLE);
-
-            if (mCloseCallback != null) {
-                mCloseCallback.onClose();
-            }
+    public void setClosed() {
+        mIsOpen = false;
+        mHistoryFrame.setVisibility(View.INVISIBLE);
+        if (mCloseCallback != null) {
+            mCloseCallback.onClose();
         }
     }
 
@@ -350,7 +347,9 @@
                 settleToOpen = releasedChild.getTop() > -(mVerticalRange / 2);
             }
 
-            if (mDragHelper.settleCapturedViewAt(0, settleToOpen ? 0 : -mVerticalRange)) {
+            // If the view is not visible, then settle it closed, not open.
+            if (mDragHelper.settleCapturedViewAt(0, settleToOpen && mIsOpen ? 0
+                    : -mVerticalRange)) {
                 ViewCompat.postInvalidateOnAnimation(DragLayout.this);
             }
         }