summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--res/layout/display.xml7
-rw-r--r--res/values-land/styles.xml2
-rw-r--r--res/values-port/styles.xml2
-rw-r--r--res/values-sw600dp-land/styles.xml2
-rw-r--r--res/values-sw600dp-port/styles.xml2
-rw-r--r--res/values-sw800dp-land/styles.xml2
-rw-r--r--res/values-sw800dp-port/styles.xml2
-rw-r--r--res/values/attr.xml2
-rw-r--r--res/values/strings.xml2
-rw-r--r--res/values/styles.xml8
-rw-r--r--src/com/android/calculator2/Calculator.java34
-rw-r--r--src/com/android/calculator2/CalculatorExpr.java18
-rw-r--r--src/com/android/calculator2/CalculatorResult.java119
-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.java146
-rw-r--r--src/com/android/calculator2/KeyMaps.java5
16 files changed, 210 insertions, 181 deletions
diff --git a/res/layout/display.xml b/res/layout/display.xml
index 2132a46..1fe2cf7 100644
--- a/res/layout/display.xml
+++ b/res/layout/display.xml
@@ -38,15 +38,16 @@
</Toolbar>
- <com.android.calculator2.CalculatorEditText
+ <com.android.calculator2.CalculatorText
android:id="@+id/formula"
- style="@style/DisplayEditTextStyle.Formula"
+ style="@style/DisplayTextStyle.Formula"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/toolbar"
- android:inputType="none"
+ android:ellipsize="none"
android:longClickable="true"
android:singleLine="true"
+ android:scrollHorizontally="true"
android:textColor="@color/display_formula_text_color"
android:textIsSelectable="false" />
diff --git a/res/values-land/styles.xml b/res/values-land/styles.xml
index 1cfcf4f..828d9ac 100644
--- a/res/values-land/styles.xml
+++ b/res/values-land/styles.xml
@@ -18,7 +18,7 @@
<!-- Styles for landscape phone (e.g. Nexus 4/5). -->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <style name="DisplayEditTextStyle.Formula">
+ <style name="DisplayTextStyle.Formula">
<item name="android:paddingTop">0dip</item>
<item name="android:paddingBottom">12dip</item>
<item name="android:paddingStart">32dip</item>
diff --git a/res/values-port/styles.xml b/res/values-port/styles.xml
index aae4ca1..3a7ad3e 100644
--- a/res/values-port/styles.xml
+++ b/res/values-port/styles.xml
@@ -18,7 +18,7 @@
<!-- Styles for portrait phone (e.g. Nexus 4/5). -->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <style name="DisplayEditTextStyle.Formula">
+ <style name="DisplayTextStyle.Formula">
<item name="android:paddingTop">8dip</item>
<item name="android:paddingBottom">24dip</item>
<item name="android:paddingStart">16dip</item>
diff --git a/res/values-sw600dp-land/styles.xml b/res/values-sw600dp-land/styles.xml
index dcbfeb4..e97f2ab 100644
--- a/res/values-sw600dp-land/styles.xml
+++ b/res/values-sw600dp-land/styles.xml
@@ -18,7 +18,7 @@
<!-- Styles for landscape 600dip-wide tablet (e.g. Nexus 7). -->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <style name="DisplayEditTextStyle.Formula">
+ <style name="DisplayTextStyle.Formula">
<item name="android:paddingTop">0dip</item>
<item name="android:paddingBottom">52dip</item>
<item name="android:paddingStart">44dip</item>
diff --git a/res/values-sw600dp-port/styles.xml b/res/values-sw600dp-port/styles.xml
index 623f4c0..9cd76ce 100644
--- a/res/values-sw600dp-port/styles.xml
+++ b/res/values-sw600dp-port/styles.xml
@@ -19,7 +19,7 @@
<!-- Styles for portrait 600dip-wide tablet (e.g. Nexus 7). -->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <style name="DisplayEditTextStyle.Formula">
+ <style name="DisplayTextStyle.Formula">
<item name="android:paddingTop">16dip</item>
<item name="android:paddingBottom">48dip</item>
<item name="android:paddingStart">44dip</item>
diff --git a/res/values-sw800dp-land/styles.xml b/res/values-sw800dp-land/styles.xml
index b834d8c..7952971 100644
--- a/res/values-sw800dp-land/styles.xml
+++ b/res/values-sw800dp-land/styles.xml
@@ -18,7 +18,7 @@
<!-- Styles for landscape 800dip-wide tablet (e.g. Nexus 10). -->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <style name="DisplayEditTextStyle.Formula">
+ <style name="DisplayTextStyle.Formula">
<item name="android:paddingTop">16dip</item>
<item name="android:paddingBottom">42dip</item>
<item name="android:paddingStart">44dip</item>
diff --git a/res/values-sw800dp-port/styles.xml b/res/values-sw800dp-port/styles.xml
index 881a033..bca0b13 100644
--- a/res/values-sw800dp-port/styles.xml
+++ b/res/values-sw800dp-port/styles.xml
@@ -18,7 +18,7 @@
<!-- Styles for portrait 800dip-wide tablet (e.g. Nexus 10). -->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <style name="DisplayEditTextStyle.Formula">
+ <style name="DisplayTextStyle.Formula">
<item name="android:paddingTop">16dip</item>
<item name="android:paddingBottom">68dip</item>
<item name="android:paddingStart">44dip</item>
diff --git a/res/values/attr.xml b/res/values/attr.xml
index 5043663..cfefc9d 100644
--- a/res/values/attr.xml
+++ b/res/values/attr.xml
@@ -17,7 +17,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android">
- <declare-styleable name="CalculatorEditText">
+ <declare-styleable name="CalculatorText">
<attr name="minTextSize" format="dimension" />
<attr name="maxTextSize" format="dimension" />
<attr name="stepTextSize" format="dimension" />
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 2b621bb..3d10202 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -75,8 +75,6 @@
<!-- Abbrev. name of radian mode [CHAR_LIMIT=5] -->
<!-- Used both as button label and for status indicator on top -->
<string name="mode_rad">rad</string>
- <!-- Ellipsis string used in display (e.g. "...". [CHAR_LIMIT=3] -->
- <string name="ellipsis">\u2026</string>
<!-- Clear operation to clear the currently entered expression. [CHAR_LIMIT=3] -->
<string name="clr">clr</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 12295e5..69a537a 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -25,14 +25,6 @@
<item name="android:windowContentOverlay">@null</item>
</style>
- <style name="DisplayEditTextStyle" parent="@android:style/Widget.Material.Light.EditText">
- <item name="android:background">@android:color/transparent</item>
- <item name="android:cursorVisible">false</item>
- <item name="android:fontFamily">sans-serif-light</item>
- <item name="android:includeFontPadding">false</item>
- <item name="android:gravity">bottom|end</item>
- </style>
-
<style name="DisplayTextStyle" parent="@android:style/Widget.Material.Light.TextView">
<item name="android:background">@android:color/transparent</item>
<item name="android:cursorVisible">false</item>
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