summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/com/android/calculator2/Calculator.java9
-rw-r--r--src/com/android/calculator2/CalculatorResult.java23
-rw-r--r--src/com/android/calculator2/Evaluator.java27
3 files changed, 36 insertions, 23 deletions
diff --git a/src/com/android/calculator2/Calculator.java b/src/com/android/calculator2/Calculator.java
index 6cf5399..ee39f9d 100644
--- a/src/com/android/calculator2/Calculator.java
+++ b/src/com/android/calculator2/Calculator.java
@@ -311,8 +311,6 @@ public class Calculator extends Activity
mEvaluator = Evaluator.getInstance(this);
mResultText.setEvaluator(mEvaluator, Evaluator.MAIN_INDEX);
- // This resultText should always use evaluateAndNotify, not requireResult().
- mResultText.setShouldRequireResult(false);
KeyMaps.setActivity(this);
mDragLayout = (DragLayout) findViewById(R.id.drag_layout);
@@ -365,8 +363,11 @@ public class Calculator extends Activity
// Just reevaluate.
redisplayFormula();
setState(CalculatorState.INIT);
- mEvaluator.requireResult(Evaluator.MAIN_INDEX, this, mResultText);
+ // Request evaluation when we know display width.
+ mResultText.setShouldRequireResult(true, this);
} else {
+ // This resultText will explicitly call evaluateAndNotify when ready.
+ mResultText.setShouldRequireResult(false, null);
redisplayAfterFormulaChange();
}
// TODO: We're currently not saving and restoring scroll position.
@@ -412,6 +413,8 @@ public class Calculator extends Activity
private void setState(CalculatorState state) {
if (mCurrentState != state) {
if (state == CalculatorState.INPUT) {
+ // We'll explicitly request evaluation from now on.
+ mResultText.setShouldRequireResult(false, null);
restoreDisplayPositions();
}
mCurrentState = state;
diff --git a/src/com/android/calculator2/CalculatorResult.java b/src/com/android/calculator2/CalculatorResult.java
index bfabfce..5c97bfa 100644
--- a/src/com/android/calculator2/CalculatorResult.java
+++ b/src/com/android/calculator2/CalculatorResult.java
@@ -98,8 +98,9 @@ public class CalculatorResult extends AlignedTextView implements MenuItem.OnMenu
// Protects the next five fields. These fields are only
// Updated by the UI thread, and read accesses by the UI thread
// sometimes do not acquire the lock.
- private int mWidthConstraint = -1;
+ private int mWidthConstraint = 0;
// Our total width in pixels minus space for ellipsis.
+ // 0 ==> uninitialized.
private float mCharWidth = 1;
// Maximum character width. For now we pretend that all characters
// have this width.
@@ -114,8 +115,8 @@ public class CalculatorResult extends AlignedTextView implements MenuItem.OnMenu
// Fraction of digit width saved by both replacing ellipsis with digit
// and avoiding scientific notation.
private boolean mShouldRequireResult = true;
- private static final int MAX_WIDTH = 100;
- // Maximum number of digits displayed.
+ private Evaluator.EvaluationListener mEvaluationListener = this;
+ // Listener to use if/when evaluation is requested.
public static final int MAX_LEADING_ZEROES = 6;
// Maximum number of leading zeroes after decimal point before we
// switch to scientific notation with negative exponent.
@@ -311,12 +312,13 @@ public class CalculatorResult extends AlignedTextView implements MenuItem.OnMenu
if (mEvaluator != null && mShouldRequireResult) {
final CalculatorExpr expr = mEvaluator.getExpr(mIndex);
if (expr != null && expr.hasInterestingOps()) {
- mEvaluator.requireResult(mIndex, this, this);
+ mEvaluator.requireResult(mIndex, mEvaluationListener, this);
}
}
}
- public void setShouldRequireResult(boolean should) {
+ public void setShouldRequireResult(boolean should, Evaluator.EvaluationListener listener) {
+ mEvaluationListener = listener;
mShouldRequireResult = should;
}
@@ -780,20 +782,13 @@ public class CalculatorResult extends AlignedTextView implements MenuItem.OnMenu
/**
* Return the maximum number of characters that will fit in the result display.
* May be called asynchronously from non-UI thread. From Evaluator.CharMetricsInfo.
+ * Returns zero if measurement hasn't completed.
*/
@Override
public int getMaxChars() {
int result;
synchronized(mWidthLock) {
- result = (int) Math.floor(mWidthConstraint / mCharWidth);
- // We can apparently finish evaluating before onMeasure in CalculatorFormula has been
- // called, in which case we get 0 or -1 as the width constraint.
- }
- if (result <= 0) {
- // Return something conservatively big, to force sufficient evaluation.
- return MAX_WIDTH;
- } else {
- return result;
+ return (int) Math.floor(mWidthConstraint / mCharWidth);
}
}
diff --git a/src/com/android/calculator2/Evaluator.java b/src/com/android/calculator2/Evaluator.java
index a37a44a..8ea518f 100644
--- a/src/com/android/calculator2/Evaluator.java
+++ b/src/com/android/calculator2/Evaluator.java
@@ -151,6 +151,7 @@ public class Evaluator implements CalculatorExpr.ExprResolver {
* the supplied string prefix.
* The prefix consists of the first len characters of string s, which is presumed to
* represent a whole number. Callable from non-UI thread.
+ * Returns zero if metrics information is not yet available.
*/
public float separatorChars(String s, int len);
/**
@@ -282,8 +283,8 @@ public class Evaluator implements CalculatorExpr.ExprResolver {
mVal = new AtomicReference<UnifiedReal>();
}
- // Currently running expression evaluator, if any. This is an AsyncEvaluator if
- // mVal.get() == null, an AsyncReevaluator otherwise.
+ // Currently running expression evaluator, if any. This is either an AsyncEvaluator
+ // (if mResultString == null or it's obsolete), or an AsyncReevaluator.
public AsyncTask mEvaluator;
// The remaining fields are valid only if an evaluation completed successfully.
@@ -449,7 +450,7 @@ public class Evaluator implements CalculatorExpr.ExprResolver {
*/
class AsyncEvaluator extends AsyncTask<Void, Void, InitialResult> {
private boolean mDm; // degrees
- private boolean mRequired; // Result was requested by user.
+ public boolean mRequired; // Result was requested by user.
private boolean mQuiet; // Suppress cancellation message.
private Runnable mTimeoutRunnable = null;
private EvaluationListener mListener; // Completion callback.
@@ -1123,8 +1124,13 @@ public class Evaluator implements CalculatorExpr.ExprResolver {
* Start optional evaluation of expression and display when ready.
* @param index of expression to be evaluated.
* Can quietly time out without a listener callback.
+ * No-op if cmi.getMaxChars() == 0.
*/
public void evaluateAndNotify(long index, EvaluationListener listener, CharMetricsInfo cmi) {
+ if (cmi.getMaxChars() == 0) {
+ // Probably shouldn't happen. If it does, we didn't promise to do anything anyway.
+ return;
+ }
if (index == MAIN_INDEX) {
if (mMainExpr.mResultString != null && !mChangedValue) {
// Already done. Just notify.
@@ -1141,13 +1147,22 @@ public class Evaluator implements CalculatorExpr.ExprResolver {
* Start required evaluation of expression at given index and call back listener when ready.
* If index is MAIN_INDEX, we may also directly display a timeout message.
* Uses longer timeouts than optional evaluation.
+ * Requires cmi.getMaxChars() != 0.
*/
public void requireResult(long index, EvaluationListener listener, CharMetricsInfo cmi) {
+ if (cmi.getMaxChars() == 0) {
+ throw new AssertionError("requireResult called too early");
+ }
ExprInfo ei = ensureExprIsCached(index);
if (ei.mResultString == null || (index == MAIN_INDEX && mChangedValue)) {
- // Restart evaluator in requested mode, i.e. with longer timeout.
- cancel(ei, true);
- evaluateResult(index, listener, cmi, true);
+ if ((ei.mEvaluator instanceof AsyncEvaluator)
+ && ((AsyncEvaluator)(ei.mEvaluator)).mRequired) {
+ // Duplicate request; ignore.
+ } else {
+ // Restart evaluator in requested mode, i.e. with longer timeout.
+ cancel(ei, true);
+ evaluateResult(index, listener, cmi, true);
+ }
} else {
notifyImmediately(index, ei, listener, cmi);
}