diff options
Diffstat (limited to 'src/com/android')
-rw-r--r-- | src/com/android/calculator2/Calculator.java | 34 | ||||
-rw-r--r-- | src/com/android/calculator2/CalculatorExpr.java | 18 | ||||
-rw-r--r-- | src/com/android/calculator2/CalculatorResult.java | 119 | ||||
-rw-r--r-- | src/com/android/calculator2/CalculatorText.java (renamed from src/com/android/calculator2/CalculatorEditText.java) | 38 | ||||
-rw-r--r-- | src/com/android/calculator2/Evaluator.java | 146 | ||||
-rw-r--r-- | src/com/android/calculator2/KeyMaps.java | 5 |
6 files changed, 199 insertions, 161 deletions
diff --git a/src/com/android/calculator2/Calculator.java b/src/com/android/calculator2/Calculator.java index 9def2a7..ed5eb6b 100644 --- a/src/com/android/calculator2/Calculator.java +++ b/src/com/android/calculator2/Calculator.java @@ -76,7 +76,7 @@ import android.webkit.WebView; import android.widget.TextView; import android.widget.Toolbar; -import com.android.calculator2.CalculatorEditText.OnTextSizeChangeListener; +import com.android.calculator2.CalculatorText.OnTextSizeChangeListener; import java.io.ByteArrayInputStream; import java.io.ObjectInputStream; @@ -88,7 +88,7 @@ import java.io.IOException; import java.text.DecimalFormatSymbols; // TODO: May eventually not need this here. public class Calculator extends Activity - implements OnTextSizeChangeListener, OnLongClickListener, CalculatorEditText.PasteListener { + implements OnTextSizeChangeListener, OnLongClickListener, CalculatorText.PasteListener { /** * Constant for an invalid resource id. @@ -178,7 +178,7 @@ public class Calculator extends Activity private View mDisplayView; private TextView mModeView; - private CalculatorEditText mFormulaEditText; + private CalculatorText mFormulaText; private CalculatorResult mResult; private ViewPager mPadViewPager; @@ -205,7 +205,7 @@ public class Calculator extends Activity mDisplayView = findViewById(R.id.display); mModeView = (TextView) findViewById(R.id.deg_rad); - mFormulaEditText = (CalculatorEditText) findViewById(R.id.formula); + mFormulaText = (CalculatorText) findViewById(R.id.formula); mResult = (CalculatorResult) findViewById(R.id.result); mPadViewPager = (ViewPager) findViewById(R.id.pad_pager); @@ -240,9 +240,9 @@ public class Calculator extends Activity } } } - mFormulaEditText.setOnKeyListener(mFormulaOnKeyListener); - mFormulaEditText.setOnTextSizeChangeListener(this); - mFormulaEditText.setPasteListener(this); + mFormulaText.setOnKeyListener(mFormulaOnKeyListener); + mFormulaText.setOnTextSizeChangeListener(this); + mFormulaText.setPasteListener(this); mDeleteButton.setOnLongClickListener(this); updateDegreeMode(mEvaluator.getDegreeMode()); if (mCurrentState == CalculatorState.EVALUATE) { @@ -304,11 +304,11 @@ public class Calculator extends Activity if (mCurrentState == CalculatorState.ERROR) { final int errorColor = getResources().getColor(R.color.calculator_error_color); - mFormulaEditText.setTextColor(errorColor); + mFormulaText.setTextColor(errorColor); mResult.setTextColor(errorColor); getWindow().setStatusBarColor(errorColor); } else { - mFormulaEditText.setTextColor( + mFormulaText.setTextColor( getResources().getColor(R.color.display_formula_text_color)); mResult.setTextColor( getResources().getColor(R.color.display_result_text_color)); @@ -438,9 +438,9 @@ public class Calculator extends Activity formatted.setSpan(new ForegroundColorSpan(Color.RED), formula.length(), formatted.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); - mFormulaEditText.setText(formatted); + mFormulaText.setText(formatted); } else { - mFormulaEditText.setText(formula); + mFormulaText.setText(formula); } } @@ -638,7 +638,7 @@ public class Calculator extends Activity // slot and small result slot. final float resultScale = 1.5f; final float resultTranslationX = -mResult.getWidth() * (resultScale - 1)/2; - // mFormulaEditText is aligned with mResult on the right. + // mFormulaText is aligned with mResult on the right. // When we enlarge it around its center, the right side // moves to the right. This compensates. float resultTranslationY = -mResult.getHeight(); @@ -646,7 +646,7 @@ public class Calculator extends Activity // Now compensate for the fact that we're // simultaenously expanding it around its center by half its height resultTranslationY += mResult.getHeight() * (resultScale - 1)/2; - final float formulaTranslationY = -mFormulaEditText.getBottom(); + final float formulaTranslationY = -mFormulaText.getBottom(); // TODO: Reintroduce textColorAnimator? // The initial and final colors seemed to be the same in L. @@ -660,7 +660,7 @@ public class Calculator extends Activity ObjectAnimator.ofFloat(mResult, View.SCALE_Y, resultScale), ObjectAnimator.ofFloat(mResult, View.TRANSLATION_X, resultTranslationX), ObjectAnimator.ofFloat(mResult, View.TRANSLATION_Y, resultTranslationY), - ObjectAnimator.ofFloat(mFormulaEditText, View.TRANSLATION_Y, + ObjectAnimator.ofFloat(mFormulaText, View.TRANSLATION_Y, formulaTranslationY)); animatorSet.setDuration( getResources().getInteger(android.R.integer.config_longAnimTime)); @@ -685,7 +685,7 @@ public class Calculator extends Activity mResult.setScaleY(resultScale); mResult.setTranslationX(resultTranslationX); mResult.setTranslationY(resultTranslationY); - mFormulaEditText.setTranslationY(formulaTranslationY); + mFormulaText.setTranslationY(formulaTranslationY); setState(CalculatorState.RESULT); } } @@ -700,9 +700,9 @@ public class Calculator extends Activity mResult.setScaleY(1.0f); mResult.setTranslationX(0.0f); mResult.setTranslationY(0.0f); - mFormulaEditText.setTranslationY(0.0f); + mFormulaText.setTranslationY(0.0f); - mFormulaEditText.requestFocus(); + mFormulaText.requestFocus(); } @Override diff --git a/src/com/android/calculator2/CalculatorExpr.java b/src/com/android/calculator2/CalculatorExpr.java index b15a8cf..955fd7b 100644 --- a/src/com/android/calculator2/CalculatorExpr.java +++ b/src/com/android/calculator2/CalculatorExpr.java @@ -571,7 +571,7 @@ class CalculatorExpr { case R.id.fun_sin: argVal = evalExpr(i+1, ec); if (isOperator(argVal.mPos, R.id.rparen)) argVal.mPos++; - ratVal = ec.mDegreeMode? BoundedRational.degreeSin(argVal.mRatVal) + ratVal = ec.mDegreeMode ? BoundedRational.degreeSin(argVal.mRatVal) : BoundedRational.sin(argVal.mRatVal); if (ratVal != null) break; return new EvalRet(argVal.mPos, @@ -579,7 +579,7 @@ class CalculatorExpr { case R.id.fun_cos: argVal = evalExpr(i+1, ec); if (isOperator(argVal.mPos, R.id.rparen)) argVal.mPos++; - ratVal = ec.mDegreeMode? BoundedRational.degreeCos(argVal.mRatVal) + ratVal = ec.mDegreeMode ? BoundedRational.degreeCos(argVal.mRatVal) : BoundedRational.cos(argVal.mRatVal); if (ratVal != null) break; return new EvalRet(argVal.mPos, @@ -587,7 +587,7 @@ class CalculatorExpr { case R.id.fun_tan: argVal = evalExpr(i+1, ec); if (isOperator(argVal.mPos, R.id.rparen)) argVal.mPos++; - ratVal = ec.mDegreeMode? BoundedRational.degreeTan(argVal.mRatVal) + ratVal = ec.mDegreeMode ? BoundedRational.degreeTan(argVal.mRatVal) : BoundedRational.tan(argVal.mRatVal); if (ratVal != null) break; CR argCR = toRadians(argVal.mVal, ec); @@ -610,7 +610,7 @@ class CalculatorExpr { case R.id.fun_arcsin: argVal = evalExpr(i+1, ec); if (isOperator(argVal.mPos, R.id.rparen)) argVal.mPos++; - ratVal = ec.mDegreeMode? BoundedRational.degreeAsin(argVal.mRatVal) + ratVal = ec.mDegreeMode ? BoundedRational.degreeAsin(argVal.mRatVal) : BoundedRational.asin(argVal.mRatVal); if (ratVal != null) break; return new EvalRet(argVal.mPos, @@ -620,7 +620,7 @@ class CalculatorExpr { case R.id.fun_arccos: argVal = evalExpr(i+1, ec); if (isOperator(argVal.mPos, R.id.rparen)) argVal.mPos++; - ratVal = ec.mDegreeMode? BoundedRational.degreeAcos(argVal.mRatVal) + ratVal = ec.mDegreeMode ? BoundedRational.degreeAcos(argVal.mRatVal) : BoundedRational.acos(argVal.mRatVal); if (ratVal != null) break; return new EvalRet(argVal.mPos, @@ -630,7 +630,7 @@ class CalculatorExpr { case R.id.fun_arctan: argVal = evalExpr(i+1, ec); if (isOperator(argVal.mPos, R.id.rparen)) argVal.mPos++; - ratVal = ec.mDegreeMode? BoundedRational.degreeAtan(argVal.mRatVal) + ratVal = ec.mDegreeMode ? BoundedRational.degreeAtan(argVal.mRatVal) : BoundedRational.atan(argVal.mRatVal); if (ratVal != null) break; return new EvalRet(argVal.mPos, @@ -725,11 +725,11 @@ class CalculatorExpr { private EvalRet evalSignedFactor(int i, EvalContext ec) throws ArithmeticException { final boolean negative = isOperator(i, R.id.op_sub); - int cpos = negative? i + 1 : i; + int cpos = negative ? i + 1 : i; EvalRet tmp = evalFactor(cpos, ec); cpos = tmp.mPos; - CR cval = negative? tmp.mVal.negate() : tmp.mVal; - BoundedRational ratVal = negative? BoundedRational.negate(tmp.mRatVal) + CR cval = negative ? tmp.mVal.negate() : tmp.mVal; + BoundedRational ratVal = negative ? BoundedRational.negate(tmp.mRatVal) : tmp.mRatVal; return new EvalRet(cpos, cval, ratVal); } diff --git a/src/com/android/calculator2/CalculatorResult.java b/src/com/android/calculator2/CalculatorResult.java index dcb39d3..ef62be3 100644 --- a/src/com/android/calculator2/CalculatorResult.java +++ b/src/com/android/calculator2/CalculatorResult.java @@ -48,8 +48,8 @@ import android.support.v4.view.ViewCompat; // 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 TextView { - final static int MAX_RIGHT_SCROLL = 100000000; - final static int INVALID = MAX_RIGHT_SCROLL + 10000; + static final int MAX_RIGHT_SCROLL = 100000000; + static final int INVALID = MAX_RIGHT_SCROLL + 10000; // A larger value is unlikely to avoid running out of space final OverScroller mScroller; final GestureDetector mGestureDetector; @@ -202,13 +202,122 @@ public class CalculatorResult extends TextView { private final int MAX_COPY_SIZE = 1000000; + // Format a result returned by Evaluator.getString() into a single + // line containing ellipses (if appropriate) and an exponent + // (if appropriate). digs is the value that was passed to + // getString and thus identifies the significance of the + // rightmost digit. + // We add two distinct kinds of exponents: + // 1) If the final result contains the leading digit we use standard + // scientific notation. + // 2) If not, we add an exponent corresponding to an interpretation + // of the final result as an integer. + // We add an ellipsis on the left if the result was truncated. + // We add ellipses and exponents in a way that leaves most digits + // in the position they would have been in had we not done so. + // This minimizes jumps as a result of scrolling. + // Result is NOT internationalized, uses "e" for exponent. + // last_included[0] is set to the position of the last digit we + // actually include; thus caller can tell whether result is exact. + public String formatResult(String res, int digs, + int maxDigs, boolean truncated, + boolean negative) { + if (truncated) { + res = KeyMaps.ELLIPSIS + res.substring(1, res.length()); + } + int decIndex = res.indexOf('.'); + int resLen = res.length(); + if (decIndex == -1 && digs != -1) { + // No decimal point displayed, and it's not just + // to the right of the last digit. + // Add an exponent to let the user track which + // digits are currently displayed. + // This is a bit tricky, since the number of displayed + // digits affects the displayed exponent, which can + // affect the room we have for mantissa digits. + // We occasionally display one digit too few. + // This is sometimes unavoidable, but we could + // avoid it in more cases. + int exp = digs > 0 ? -digs : -digs - 1; + // Can be used as TYPE (2) EXPONENT. + // -1 accounts for decimal point. + int msd; // Position of most significant digit in res + // or indication its outside res. + boolean hasPoint = false; + if (truncated) { + msd = -1; + } else { + msd = Evaluator.getMsdPos(res); // INVALID_MSD is OK + } + if (msd < maxDigs - 1 && msd >= 0) { + // TYPE (1) EXPONENT computation and transformation: + // Leading digit is in display window. + // Use standard calculator scientific notation + // with one digit to the left of the decimal point. + // Insert decimal point and delete leading zeroes. + String fraction = res.substring(msd + 1, resLen); + res = (negative ? "-" : "") + + res.substring(msd, msd+1) + "." + fraction; + exp += resLen - msd - 1; + // Original exp was correct for decimal point at right + // of fraction. Adjust by length of fraction. + resLen = res.length(); + hasPoint = true; + } + if (exp != 0 || truncated) { + // Actually add the exponent of either type: + String expAsString = Integer.toString(exp); + int expDigits = expAsString.length(); + int dropDigits = expDigits + 1; + // Drop digits even if there is room. + // Otherwise the scrolling gets jumpy. + if (dropDigits >= resLen - 1) { + dropDigits = Math.max(resLen - 2, 0); + // Jumpy is better than no mantissa. + } + if (!hasPoint) { + // Special handling for TYPE(2) EXPONENT: + exp += dropDigits; + expAsString = Integer.toString(exp); + // Adjust for digits we are about to drop + // to drop to make room for exponent. + // This can affect the room we have for the + // mantissa. We adjust only for positive exponents, + // when it could otherwise result in a truncated + // displayed result. + if (exp > 0 && expAsString.length() > expDigits) { + // ++expDigits; (dead code) + ++dropDigits; + ++exp; + // This cannot increase the length a second time. + } + } + res = res.substring(0, resLen - dropDigits); + res = res + "e" + expAsString; + } // else don't add zero exponent + } + return res; + } + + // Get formatted, but not internationalized, result from + // mEvaluator. + private String getFormattedResult(int pos, int maxSize) { + final boolean truncated[] = new boolean[1]; + final boolean negative[] = new boolean[1]; + final int requested_prec[] = {pos}; + final String raw_res = mEvaluator.getString(requested_prec, maxSize, + truncated, negative); + return formatResult(raw_res, requested_prec[0], maxSize, + truncated[0], negative[0]); + } + // Return entire result (within reason) up to current displayed precision. public String getFullText() { if (!mValid) return ""; if (!mScrollable) return getText().toString(); int currentCharPos = getCurrentCharPos(); return KeyMaps.translateResult( - mEvaluator.getString(currentCharPos, MAX_COPY_SIZE)); + getFormattedResult(currentCharPos, MAX_COPY_SIZE)); } public boolean fullTextIsExact() { @@ -233,7 +342,7 @@ public class CalculatorResult extends TextView { synchronized(mWidthLock) { result = 2 * mWidthConstraint / (3 * mCharWidth); // We can apparently finish evaluating before - // onMeasure in CalculatorEditText has been called, in + // onMeasure in CalculatorText has been called, in // which case we get 0 or -1 as the width constraint. } if (result <= 0) { @@ -259,7 +368,7 @@ public class CalculatorResult extends TextView { void redisplay() { int currentCharPos = getCurrentCharPos(); int maxChars = getMaxChars(); - String result = mEvaluator.getString(currentCharPos, maxChars); + String result = getFormattedResult(currentCharPos, maxChars); int epos = result.indexOf('e'); result = KeyMaps.translateResult(result); if (epos > 0 && result.indexOf('.') == -1) { diff --git a/src/com/android/calculator2/CalculatorEditText.java b/src/com/android/calculator2/CalculatorText.java index b916a26..01f234b 100644 --- a/src/com/android/calculator2/CalculatorEditText.java +++ b/src/com/android/calculator2/CalculatorText.java @@ -37,14 +37,13 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; -import android.widget.EditText; import android.widget.TextView; /** - * EditText adapted for Calculator display. + * TextView adapted for Calculator display. */ -public class CalculatorEditText extends EditText implements View.OnLongClickListener{ +public class CalculatorText extends TextView implements View.OnLongClickListener{ private final ActionMode.Callback mPasteActionModeCallback = @@ -115,24 +114,24 @@ public class CalculatorEditText extends EditText implements View.OnLongClickList private int mWidthConstraint = -1; private OnTextSizeChangeListener mOnTextSizeChangeListener; - public CalculatorEditText(Context context) { + public CalculatorText(Context context) { this(context, null); } - public CalculatorEditText(Context context, AttributeSet attrs) { + public CalculatorText(Context context, AttributeSet attrs) { this(context, attrs, 0); } - public CalculatorEditText(Context context, AttributeSet attrs, int defStyle) { + public CalculatorText(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); final TypedArray a = context.obtainStyledAttributes( - attrs, R.styleable.CalculatorEditText, defStyle, 0); + attrs, R.styleable.CalculatorText, defStyle, 0); mMaximumTextSize = a.getDimension( - R.styleable.CalculatorEditText_maxTextSize, getTextSize()); + R.styleable.CalculatorText_maxTextSize, getTextSize()); mMinimumTextSize = a.getDimension( - R.styleable.CalculatorEditText_minTextSize, getTextSize()); - mStepTextSize = a.getDimension(R.styleable.CalculatorEditText_stepTextSize, + R.styleable.CalculatorText_minTextSize, getTextSize()); + mStepTextSize = a.getDimension(R.styleable.CalculatorText_stepTextSize, (mMaximumTextSize - mMinimumTextSize) / 3); a.recycle(); @@ -141,9 +140,9 @@ public class CalculatorEditText extends EditText implements View.OnLongClickList // setCustomSelectionActionModeCallback. setOnLongClickListener(this); - if (isFocusable()) { - setMovementMethod(ScrollingMovementMethod.getInstance()); - } + // Enable scrolling + setMovementMethod(ScrollingMovementMethod.getInstance()); + setTextSize(TypedValue.COMPLEX_UNIT_PX, mMaximumTextSize); setMinHeight(getLineHeight() + getCompoundPaddingBottom() + getCompoundPaddingTop()); } @@ -166,23 +165,10 @@ public class CalculatorEditText extends EditText implements View.OnLongClickList public int getWidthConstraint() { return mWidthConstraint; } @Override - public Parcelable onSaveInstanceState() { - super.onSaveInstanceState(); - - // EditText will freeze any text with a selection regardless of getFreezesText() -> - // return null to prevent any state from being preserved at the instance level. - return null; - } - - @Override protected void onTextChanged(CharSequence text, int start, int lengthBefore, int lengthAfter) { super.onTextChanged(text, start, lengthBefore, lengthAfter); final int textLength = text.length(); - if (getSelectionStart() != textLength || getSelectionEnd() != textLength) { - // Pin the selection to the end of the current text. - setSelection(textLength); - } setTextSize(TypedValue.COMPLEX_UNIT_PX, getVariableTextSize(text.toString())); } diff --git a/src/com/android/calculator2/Evaluator.java b/src/com/android/calculator2/Evaluator.java index 25cadae..b4a73c6 100644 --- a/src/com/android/calculator2/Evaluator.java +++ b/src/com/android/calculator2/Evaluator.java @@ -124,8 +124,8 @@ class Evaluator { private final char decimalPt = DecimalFormatSymbols.getInstance().getDecimalSeparator(); - private final static int MAX_DIGITS = 100; // Max digits displayed at once. - private final static int EXTRA_DIGITS = 20; + private static final int MAX_DIGITS = 100; // Max digits displayed at once. + private static final int EXTRA_DIGITS = 20; // Extra computed digits to minimize probably we will have // to change our minds about digits we already displayed. // (The correct digits are technically not computable using our @@ -137,7 +137,7 @@ class Evaluator { // We do use these extra digits to display while we are // computing the correct answer. Thus they may be // temporarily visible. - private final static int PRECOMPUTE_DIGITS = 20; + private static final int PRECOMPUTE_DIGITS = 20; // Extra digits computed to minimize // reevaluations during scrolling. @@ -153,12 +153,12 @@ class Evaluator { private int mCacheDigsReq; // Number of digits that have been // requested. Only touched by UI // thread. - private final int INVALID_MSD = Integer.MAX_VALUE; + public static final int INVALID_MSD = Integer.MAX_VALUE; private int mMsd = INVALID_MSD; // Position of most significant digit // in current cached result, if determined. // This is just the index in mCache // holding the msd. - private final int MAX_MSD_PREC = 100; + private static final int MAX_MSD_PREC = 100; // The largest number of digits to the right // of the decimal point to which we will // evaluate to compute proper scientific @@ -332,10 +332,10 @@ class Evaluator { } @Override protected void onPreExecute() { - long timeout = mRequired? mTimeout : mQuickTimeout; + long timeout = mRequired ? mTimeout : mQuickTimeout; if (timeout != 0) { mTimeoutHandler.postDelayed( - (mRequired? mTimeoutRunnable : mQuickTimeoutRunnable), + (mRequired ? mTimeoutRunnable : mQuickTimeoutRunnable), timeout); } } @@ -491,15 +491,14 @@ class Evaluator { } res = KeyMaps.translateResult(res); if (need_ellipsis) { - res += mCalculator.getResources() - .getString(R.string.ellipsis); + res += KeyMaps.ELLIPSIS; } return res; } // Return the most significant digit position in the given string // or INVALID_MSD. - private int getMsdPos(String s) { + public static int getMsdPos(String s) { int len = s.length(); int nonzeroPos = -1; for (int i = 0; i < len; ++i) { @@ -563,44 +562,61 @@ class Evaluator { return res; } - // TODO: The following should be refactored, particularly since - // maxDigs should probably depend on the width of characters in - // the result. - // And we should try to at leas factor out the code to add the exponent. - // - // Return result to digs digits to the right of the decimal point - // (minus any space occupied by exponent included in the result). + private static final int MIN_DIGS = 5; + // Leave at least this many digits from the whole number + // part on the screen, to avoid silly displays like 1E1. + // Return result to exactly prec[0] digits to the right of the + // decimal point. // The result should be no longer than maxDigs. + // No exponent or other indication of precision is added. // The result is returned immediately, based on the // current cache contents, but it may contain question // marks for unknown digits. It may also use uncertain // digits within EXTRA_DIGITS. If either of those occurred, // schedule a reevaluation and redisplay operation. + // Uncertain digits never appear to the left of the decimal point. // digs may be negative to only retrieve digits to the left - // of the decimal point. (digs = 0 means we include - // the decimal point, but nothing to the right. Digs = -1 + // of the decimal point. (prec[0] = 0 means we include + // the decimal point, but nothing to the right. prec[0] = -1 // means we drop the decimal point and start at the ones // position. Should not be invoked if mVal is null. - String getString(int digs, int maxDigs) { + // This essentially just returns a substring of the full result; + // a leading minus sign or leading digits can be dropped. + // Result uses US conventions; is NOT internationalized. + // We set negative[0] if the number as a whole is negative, + // since we may drop the minus sign. + // We set truncated[0] if leading nonzero digits were dropped. + // getRational() can be used to determine whether the result + // is exact, or whether we dropped trailing digits. + // If the requested prec[0] value is out of range, we update + // it in place and use the updated value. + public String getString(int[] prec, int maxDigs, + boolean[] truncated, boolean[] negative) { + int digs = prec[0]; mLastDigs = digs; // Make sure we eventually get a complete answer ensureCachePrec(digs + EXTRA_DIGITS); if (mCache == null) { // Nothing to do now; seems to happen on rare occasion - // with weird user input timing; will be fixed later. + // with weird user input timing; + // Will repair itself in a jiffy. return getPadding(1); } // Compute an appropriate substring of mCache. // We avoid returning a huge string to minimize string // allocation during scrolling. // Pad as needed. - boolean truncated = false; // Leading digits dropped. - int len = mCache.length(); - // Don't scroll left past leftmost digit in mCache. + final int len = mCache.length(); + final boolean myNegative = mCache.charAt(0) == '-'; + negative[0] = myNegative; + // Don't scroll left past leftmost digits in mCache + // unless that still leaves an integer. int integralDigits = len - mCacheDigs; // includes 1 for dec. pt - if (mCache.charAt(0) == '-') --integralDigits; - if (digs < -integralDigits + 1) digs = -integralDigits + 1; + if (myNegative) --integralDigits; + int minDigs = Math.min(-integralDigits + MIN_DIGS, -1); + digs = Math.max(digs, minDigs); + prec[0] = digs; int offset = mCacheDigs - digs; // trailing digits to drop int deficit = 0; // The number of digits we're short if (offset < 0) { @@ -612,11 +628,8 @@ class Evaluator { int startIndx = (endIndx + deficit <= maxDigs) ? 0 : endIndx + deficit - maxDigs; - String res; - if (startIndx != 0) { - truncated = true; - } - res = mCache.substring(startIndx, endIndx); + truncated[0] = (startIndx > getMsd()); + String res = mCache.substring(startIndx, endIndx); if (deficit > 0) { res = res + getPadding(deficit); // Since we always compute past the decimal point, @@ -624,77 +637,6 @@ class Evaluator { // should go, and the rest of this can treat the // made-up symbols as though they were digits. } - // Include exponent if necessary. - // Replace least significant digits as necessary. - if (res.indexOf('.') == -1 && digs != 1) { - // No decimal point displayed, and it's not just - // to the right of the last digit. - // Add an exponent to let the user track which - // digits are currently displayed. - // This is a bit tricky, since the number of displayed - // digits affects the displayed exponent, which can - // affect the room we have for mantissa digits. - // We occasionally display one digit too few. - // This is sometimes unavoidable, but we could - // avoid it in more cases. - int exp = (digs > 0)? -digs : -digs - 1; - // accounts for decimal point - int msd = getMsd(); - boolean hasPoint = false; - final int minFractionDigits = 6; - if (msd < endIndx - minFractionDigits && msd >= startIndx) { - // Leading digit is in display window - // Use standard calculator scientific notation - // with one digit to the left of the decimal point. - // Insert decimal point and delete leading zeroes. - int hasMinus = mCache.charAt(0) == '-'? 1 : 0; - int resLen = res.length(); - int resZeroes = leadingZeroes(res); - String fraction = - res.substring(msd+1 - startIndx, - resLen - 1 - hasMinus); - res = (hasMinus != 0? "-" : "") - + mCache.substring(msd, msd+1) + "." - + fraction; - exp += resLen - resZeroes - 1 - hasMinus; - // Decimal point moved across original res, except for - // leading digit and zeroes, and possibly minus sign. - truncated = false; // in spite of dropping leading 0s - hasPoint = true; - } - if (exp != 0 || truncated) { - String expAsString = Integer.toString(exp); - int expDigits = expAsString.length(); - int resLen = res.length(); - int dropDigits = resLen + expDigits + 1 - maxDigs; - if (dropDigits < 0) { - dropDigits = 0; - } else { - if (!hasPoint) { - exp += dropDigits; - // Adjust for digits we are about to drop - // to drop to make room for exponent. - // This can affect the room we have for the - // mantissa. We adjust only for positive exponents, - // when it could otherwise result in a truncated - // displayed result. - if (exp > 0 && dropDigits > 0 && - Integer.toString(exp).length() > expDigits) { - // ++expDigits; (dead code) - ++dropDigits; - ++exp; - // This cannot increase the length a second time. - } - } - res = res.substring(0, resLen - dropDigits); - } - res = res + "e" + exp; - } // else don't add zero exponent - } - if (truncated) { - res = mCalculator.getResources().getString(R.string.ellipsis) - + res.substring(1, res.length()); - } return res; } diff --git a/src/com/android/calculator2/KeyMaps.java b/src/com/android/calculator2/KeyMaps.java index 99f4124..493ec01 100644 --- a/src/com/android/calculator2/KeyMaps.java +++ b/src/com/android/calculator2/KeyMaps.java @@ -101,6 +101,8 @@ public class KeyMaps { public static final int NOT_DIGIT = 10; + public static final String ELLIPSIS = "\u2026"; + // Map key id to digit or NOT_DIGIT // Pure function. public static int digVal(int id) { @@ -293,8 +295,7 @@ public class KeyMaps { sOutputForResultChar.put('e', "E"); sOutputForResultChar.put('E', "E"); sOutputForResultChar.put('.', String.valueOf(mDecimalPt)); - sOutputForResultChar.put(res.getString(R.string.ellipsis).charAt(0), - res.getString(R.string.ellipsis)); + sOutputForResultChar.put(ELLIPSIS.charAt(0), ELLIPSIS); sOutputForResultChar.put('/', "/"); // Translate numbers for fraction display, but not // the separating slash, which appears to be |