Merge "Arrange for evaluateAndNotify calls at the right time." into ub-calculator-euler
diff --git a/src/com/android/calculator2/Calculator.java b/src/com/android/calculator2/Calculator.java
index f13a9ed..ce11d7a 100644
--- a/src/com/android/calculator2/Calculator.java
+++ b/src/com/android/calculator2/Calculator.java
@@ -402,16 +402,15 @@
             showAndMaybeHideToolbar();
         }
 
+        redisplayFormula();
         if (mCurrentState != CalculatorState.INPUT) {
             // Just reevaluate.
-            redisplayFormula();
             setState(CalculatorState.INIT);
             // Request evaluation when we know display width.
-            mResultText.setShouldRequireResult(true, this);
+            mResultText.setShouldEvaluateResult(CalculatorResult.SHOULD_REQUIRE, this);
         } else {
             // This resultText will explicitly call evaluateAndNotify when ready.
-            mResultText.setShouldRequireResult(false, null);
-            redisplayAfterFormulaChange();
+            mResultText.setShouldEvaluateResult(CalculatorResult.SHOULD_EVALUATE, this);
         }
         // TODO: We're currently not saving and restoring scroll position.
         //       We probably should.  Details may require care to deal with:
@@ -457,7 +456,7 @@
         if (mCurrentState != state) {
             if (state == CalculatorState.INPUT) {
                 // We'll explicitly request evaluation from now on.
-                mResultText.setShouldRequireResult(false, null);
+                mResultText.setShouldEvaluateResult(CalculatorResult.SHOULD_NOT_EVALUATE, null);
                 restoreDisplayPositions();
             }
             mCurrentState = state;
@@ -722,6 +721,13 @@
         addKeyToExpr(id);
     }
 
+    public void evaluateInstantIfNecessary() {
+        if (mCurrentState == CalculatorState.INPUT
+                && mEvaluator.getExpr(Evaluator.MAIN_INDEX).hasInterestingOps()) {
+            mEvaluator.evaluateAndNotify(Evaluator.MAIN_INDEX, this, mResultText);
+        }
+    }
+
     private void redisplayAfterFormulaChange() {
         // TODO: Could do this more incrementally.
         redisplayFormula();
@@ -731,9 +737,7 @@
             // Force reevaluation when text is deleted, even if expression is unchanged.
             mEvaluator.touch();
         } else {
-            if (mEvaluator.getExpr(Evaluator.MAIN_INDEX).hasInterestingOps()) {
-                mEvaluator.evaluateAndNotify(Evaluator.MAIN_INDEX, this, mResultText);
-            }
+            evaluateInstantIfNecessary();
         }
     }
 
@@ -806,9 +810,8 @@
                 showAndMaybeHideToolbar();
                 setState(CalculatorState.INPUT);
                 mResultText.clear();
-                if (!haveUnprocessed()
-                        && mEvaluator.getExpr(Evaluator.MAIN_INDEX).hasInterestingOps()) {
-                    mEvaluator.evaluateAndNotify(mEvaluator.MAIN_INDEX, this, mResultText);
+                if (!haveUnprocessed()) {
+                    evaluateInstantIfNecessary();
                 }
                 return;
             default:
diff --git a/src/com/android/calculator2/CalculatorResult.java b/src/com/android/calculator2/CalculatorResult.java
index a677b5e..5a23c01 100644
--- a/src/com/android/calculator2/CalculatorResult.java
+++ b/src/com/android/calculator2/CalculatorResult.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.os.Build;
+import android.support.annotation.IntDef;
 import android.support.v4.content.ContextCompat;
 import android.support.v4.os.BuildCompat;
 import android.text.Layout;
@@ -45,6 +46,9 @@
 import android.widget.OverScroller;
 import android.widget.Toast;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 // A text widget that is "infinitely" scrollable to the right,
 // and obtains the text to display via a callback to Logic.
 public class CalculatorResult extends AlignedTextView implements MenuItem.OnMenuItemClickListener,
@@ -114,7 +118,14 @@
     private float mNoEllipsisCredit;
                             // Fraction of digit width saved by both replacing ellipsis with digit
                             // and avoiding scientific notation.
-    private boolean mShouldRequireResult = true;
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({SHOULD_REQUIRE, SHOULD_EVALUATE, SHOULD_NOT_EVALUATE})
+    public @interface EvaluationRequest {}
+    public static final int SHOULD_REQUIRE = 2;
+    public static final int SHOULD_EVALUATE = 1;
+    public static final int SHOULD_NOT_EVALUATE = 0;
+    @EvaluationRequest private int mEvaluationRequest = SHOULD_REQUIRE;
+                            // Should we evaluate when layout completes, and how?
     private Evaluator.EvaluationListener mEvaluationListener = this;
                             // Listener to use if/when evaluation is requested.
     public static final int MAX_LEADING_ZEROES = 6;
@@ -313,17 +324,26 @@
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
 
-        if (mEvaluator != null && mShouldRequireResult) {
+        if (mEvaluator != null && mEvaluationRequest != SHOULD_NOT_EVALUATE) {
             final CalculatorExpr expr = mEvaluator.getExpr(mIndex);
             if (expr != null && expr.hasInterestingOps()) {
-                mEvaluator.requireResult(mIndex, mEvaluationListener, this);
+                if (mEvaluationRequest == SHOULD_REQUIRE) {
+                    mEvaluator.requireResult(mIndex, mEvaluationListener, this);
+                } else {
+                    mEvaluator.evaluateAndNotify(mIndex, mEvaluationListener, this);
+                }
             }
         }
     }
 
-    public void setShouldRequireResult(boolean should, Evaluator.EvaluationListener listener) {
+    /**
+     * Specify whether we should evaluate result on layout.
+     * @param should one of SHOULD_REQUIRE, SHOULD_EVALUATE, SHOULD_NOT_EVALUATE
+     */
+    public void setShouldEvaluateResult(@EvaluationRequest int request,
+            Evaluator.EvaluationListener listener) {
         mEvaluationListener = listener;
-        mShouldRequireResult = should;
+        mEvaluationRequest = request;
     }
 
     // From Evaluator.CharMetricsInfo.
@@ -1113,4 +1133,4 @@
                 return false;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/src/com/android/calculator2/Evaluator.java b/src/com/android/calculator2/Evaluator.java
index 77c762d..df36d49 100644
--- a/src/com/android/calculator2/Evaluator.java
+++ b/src/com/android/calculator2/Evaluator.java
@@ -240,10 +240,10 @@
 
     // The largest number of digits to the right of the decimal point to which we will evaluate to
     // compute proper scientific notation for values close to zero.  Chosen to ensure that we
-    // always to better than IEEE double precision at identifying nonzeros.
-    // This used only when we cannot a prior determine the most significant digit position, as
+    // always to better than IEEE double precision at identifying nonzeros. And then some.
+    // This is used only when we cannot a priori determine the most significant digit position, as
     // we always can if we have a rational representation.
-    private static final int MAX_MSD_PREC_OFFSET = 320;
+    private static final int MAX_MSD_PREC_OFFSET = 1100;
 
     // If we can replace an exponent by this many leading zeroes, we do so.  Also used in
     // estimating exponent size for truncating short representation.
@@ -430,7 +430,7 @@
      * Maximum result bit length for unrequested, speculative evaluations.
      * Also used to bound evaluation precision for small non-zero fractions.
      */
-    private static final int QUICK_MAX_RESULT_BITS = 50000;
+    private static final int QUICK_MAX_RESULT_BITS = 150000;
 
     private void displayTimeoutMessage(boolean longTimeout) {
         AlertDialogFragment.showMessageDialog(mActivity, R.string.dialog_timeout,
diff --git a/src/com/android/calculator2/HistoryFragment.java b/src/com/android/calculator2/HistoryFragment.java
index 5be3452..1d13a98 100644
--- a/src/com/android/calculator2/HistoryFragment.java
+++ b/src/com/android/calculator2/HistoryFragment.java
@@ -198,6 +198,9 @@
 
         mEvaluator.cancelAll(true);
         super.onDestroy();
+        // FIXME: There are probably better ways to do this. But we can end up cancelling
+        // an in-progress evaluation for the main expression that we have to restart.
+        ((Calculator)(getActivity())).evaluateInstantIfNecessary();
     }
 
     private void initializeController() {