Always calculate textSize in CalculatorText#onMeasure
am: 0ace4eb854
* commit '0ace4eb8542b090864944b9f9d8e5e7af7898436':
Always calculate textSize in CalculatorText#onMeasure
diff --git a/src/com/android/calculator2/BoundedRational.java b/src/com/android/calculator2/BoundedRational.java
index dc132f6..383e59d 100644
--- a/src/com/android/calculator2/BoundedRational.java
+++ b/src/com/android/calculator2/BoundedRational.java
@@ -35,7 +35,7 @@
// much faster.
// TODO: Maybe eventually make this extend Number?
- private static final int MAX_SIZE = 800; // total, in bits
+ private static final int MAX_SIZE = 2000; // total, in bits
private final BigInteger mNum;
private final BigInteger mDen;
@@ -70,11 +70,11 @@
/**
* Convert to readable String.
- * Intended for output output to user. More expensive, less useful for debugging than
+ * Intended for output to user. More expensive, less useful for debugging than
* toString(). Not internationalized.
*/
public String toNiceString() {
- BoundedRational nicer = reduce().positiveDen();
+ final BoundedRational nicer = reduce().positiveDen();
String result = nicer.mNum.toString();
if (!nicer.mDen.equals(BigInteger.ONE)) {
result += "/" + nicer.mDen;
@@ -90,6 +90,33 @@
}
/**
+ * Return a string with n copies of c.
+ */
+ private static String repeat(char c, int n) {
+ final StringBuilder result = new StringBuilder();
+ for (int i = 0; i < n; ++i) {
+ result.append(c);
+ }
+ return result.toString();
+ }
+
+ /*
+ * Returns a truncated (rounded towards 0) representation of the result.
+ * Includes n digits to the right of the decimal point.
+ * @param n result precision, >= 0
+ */
+ public String toString(int n) {
+ String digits = mNum.abs().multiply(BigInteger.TEN.pow(n)).divide(mDen.abs()).toString();
+ int len = digits.length();
+ if (len < n + 1) {
+ digits = repeat('0', n + 1 - len) + digits;
+ len = n + 1;
+ }
+ return (signum() < 0 ? "-" : "") + digits.substring(0, len - n) + "."
+ + digits.substring(len - n);
+ }
+
+ /**
* Return a double approximation.
* Primarily for debugging.
*/
diff --git a/src/com/android/calculator2/Calculator.java b/src/com/android/calculator2/Calculator.java
index dc08612..4f0de6c 100644
--- a/src/com/android/calculator2/Calculator.java
+++ b/src/com/android/calculator2/Calculator.java
@@ -939,8 +939,8 @@
* Map them to the appropriate button pushes when possible. Leftover characters
* are added to mUnprocessedChars, which is presumed to immediately precede the newly
* added characters.
- * @param moreChars Characters to be added.
- * @param explicit These characters were explicitly typed by the user, not pasted.
+ * @param moreChars characters to be added
+ * @param explicit these characters were explicitly typed by the user, not pasted
*/
private void addChars(String moreChars, boolean explicit) {
if (mUnprocessedChars != null) {
diff --git a/src/com/android/calculator2/CalculatorExpr.java b/src/com/android/calculator2/CalculatorExpr.java
index e2f6bee..59c800e 100644
--- a/src/com/android/calculator2/CalculatorExpr.java
+++ b/src/com/android/calculator2/CalculatorExpr.java
@@ -1130,6 +1130,15 @@
val = v;
ratVal = rv;
}
+ /*
+ * Return decimal String result to the indicated precision.
+ * For rational values this is the exactly truncated result.
+ * Otherwise the error is < 1 in the last included digit.
+ * @param precOffset Always non-negative. 1 is accurate 1/10, 2 means 1/100, etc.
+ */
+ public String toString(int precOffset) {
+ return ratVal == null ? val.toString(precOffset) : ratVal.toString(precOffset);
+ }
}
/**
diff --git a/src/com/android/calculator2/CalculatorResult.java b/src/com/android/calculator2/CalculatorResult.java
index 646b772..84ac36a 100644
--- a/src/com/android/calculator2/CalculatorResult.java
+++ b/src/com/android/calculator2/CalculatorResult.java
@@ -67,16 +67,16 @@
// left of the display. Zero means decimal point is barely displayed
// on the right.
private int mLastPos; // Position already reflected in display. Pixels.
- private int mMinPos; // Minimum position before all digits disappear off the right. Pixels.
+ private int mMinPos; // Minimum position to avoid unnecessary blanks on the left. Pixels.
private int mMaxPos; // Maximum position before we start displaying the infinite
// sequence of trailing zeroes on the right. Pixels.
+ private int mWholeLen; // Length of the whole part of current result.
// In the following, we use a suffix of Offset to denote a character position in a numeric
// string relative to the decimal point. Positive is to the right and negative is to
// the left. 1 = tenths position, -1 = units. Integer.MAX_VALUE is sometimes used
// for the offset of the last digit in an a nonterminating decimal expansion.
// We use the suffix "Index" to denote a zero-based index into a string representing a
// result.
- // TODO: Apply the same convention to other classes.
private int mMaxCharOffset; // Character offset from decimal point of rightmost digit
// that should be displayed. Essentially the same as
private int mLsdOffset; // Position of least-significant digit in result
@@ -105,6 +105,14 @@
// have a decimal point and no ellipsis.
// We assume that we do not drop digits to make room for the decimal
// point in ordinary scientific notation. Thus >= 1.
+ private static final int MAX_COPY_EXTRA = 100;
+ // The number of extra digits we are willing to compute to copy
+ // a result as an exact number.
+ private static final int MAX_RECOMPUTE_DIGITS = 2000;
+ // The maximum number of digits we're willing to recompute in the UI
+ // thread. We only do this for known rational results, where we
+ // can bound the computation cost.
+
private ActionMode mActionMode;
private final ForegroundColorSpan mExponentColorSpan;
@@ -265,13 +273,13 @@
}
return;
}
- int wholeLen = truncatedWholePart.length();
+ mWholeLen = truncatedWholePart.length();
int negative = truncatedWholePart.charAt(0) == '-' ? 1 : 0;
- if (msdIndex > wholeLen && msdIndex <= wholeLen + 3) {
+ if (msdIndex > mWholeLen && msdIndex <= mWholeLen + 3) {
// Avoid tiny negative exponent; pretend msdIndex is just to the right of decimal point.
- msdIndex = wholeLen - 1;
+ msdIndex = mWholeLen - 1;
}
- int minCharOffset = msdIndex - wholeLen;
+ int minCharOffset = msdIndex - mWholeLen;
// Position of leftmost significant digit relative to dec. point.
// Usually negative.
mMaxCharOffset = MAX_RIGHT_SCROLL; // How far does it make sense to scroll right?
@@ -338,7 +346,7 @@
* Unlike Evaluator.getMsdIndexOf, we treat a final 1 as significant.
*/
public static int getNaiveMsdIndexOf(String s) {
- int len = s.length();
+ final int len = s.length();
for (int i = 0; i < len; ++i) {
char c = s.charAt(i);
if (c != '-' && c != '.' && c != '0') {
@@ -353,10 +361,10 @@
// to getString and thus identifies the significance of the rightmost digit.
// A value of 1 means the rightmost digits corresponds to tenths.
// maxDigs is the maximum number of characters in the result.
- // We set lastDisplayedOffset[0] to the offset of the last digit actually appearing in
- // the display.
+ // If lastDisplayedOffset is not null, we set lastDisplayedOffset[0] to the offset of
+ // the last digit actually appearing in the display.
// If forcePrecision is true, we make sure that the last displayed digit corresponds to
- // precOffset, and allow maxDigs to be exceeded in assing the exponent.
+ // precOffset, and allow maxDigs to be exceeded in adding the exponent.
// 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
@@ -376,7 +384,9 @@
// Ellipsis may be removed again in the type(1) scientific notation case.
}
final int decIndex = result.indexOf('.');
- lastDisplayedOffset[0] = precOffset;
+ if (lastDisplayedOffset != null) {
+ lastDisplayedOffset[0] = precOffset;
+ }
if ((decIndex == -1 || msdIndex != Evaluator.INVALID_MSD
&& msdIndex - decIndex > MAX_LEADING_ZEROES + 1) && precOffset != -1) {
// No decimal point displayed, and it's not just to the right of the last digit,
@@ -433,7 +443,9 @@
}
}
result = result.substring(0, result.length() - dropDigits);
- lastDisplayedOffset[0] -= dropDigits;
+ if (lastDisplayedOffset != null) {
+ lastDisplayedOffset[0] -= dropDigits;
+ }
}
result = result + "E" + Integer.toString(exponent);
}
@@ -445,7 +457,7 @@
* @param precOffset requested position (1 = tenths) of last included digit.
* @param maxSize Maximum number of characters (more or less) in result.
* @param lastDisplayedOffset Zeroth entry is set to actual offset of last included digit,
- * after adjusting for exponent, etc.
+ * after adjusting for exponent, etc. May be null.
* @param forcePrecision Ensure that last included digit is at pos, at the expense
* of treating maxSize as a soft limit.
*/
@@ -460,14 +472,14 @@
lastDisplayedOffset, forcePrecision);
}
- // Return entire result (within reason) up to current displayed precision.
+ /**
+ * Return entire result (within reason) up to current displayed precision.
+ */
public String getFullText() {
if (!mValid) return "";
if (!mScrollable) return getText().toString();
- int currentCharOffset = getCurrentCharOffset();
- int unused[] = new int[1];
return KeyMaps.translateResult(getFormattedResult(mLastDisplayedOffset, MAX_COPY_SIZE,
- unused, true));
+ null, true));
}
public boolean fullTextIsExact() {
@@ -476,6 +488,27 @@
}
/**
+ * Get entire result up to current displayed precision, or up to MAX_COPY_EXTRA additional
+ * digits, if it will lead to an exact result.
+ */
+ public String getFullCopyText() {
+ if (!mValid
+ || mLsdOffset == Integer.MAX_VALUE
+ || fullTextIsExact()
+ || mWholeLen > MAX_RECOMPUTE_DIGITS
+ || mWholeLen + mLsdOffset > MAX_RECOMPUTE_DIGITS
+ || mLsdOffset - mLastDisplayedOffset > MAX_COPY_EXTRA) {
+ return getFullText();
+ }
+ // It's reasonable to compute and copy the exact result instead.
+ final int nonNegLsdOffset = Math.max(0, mLsdOffset);
+ final String rawResult = mEvaluator.getRational().toString(nonNegLsdOffset);
+ final String formattedResult = formatResult(rawResult, nonNegLsdOffset, MAX_COPY_SIZE,
+ false, rawResult.charAt(0) == '-', null, true);
+ return KeyMaps.translateResult(formattedResult);
+ }
+
+ /**
* Return the maximum number of characters that will fit in the result display.
* May be called asynchronously from non-UI thread.
*/
@@ -582,9 +615,14 @@
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_copy:
- copyContent();
- mode.finish();
- return true;
+ if (mEvaluator.reevaluationInProgress()) {
+ // Refuse to copy placeholder characters.
+ return false;
+ } else {
+ copyContent();
+ mode.finish();
+ return true;
+ }
default:
return false;
}
@@ -638,7 +676,7 @@
}
private void copyContent() {
- final CharSequence text = getFullText();
+ final CharSequence text = getFullCopyText();
ClipboardManager clipboard =
(ClipboardManager) getContext().getSystemService(Context.CLIPBOARD_SERVICE);
// We include a tag URI, to allow us to recognize our own results and handle them
diff --git a/src/com/android/calculator2/Evaluator.java b/src/com/android/calculator2/Evaluator.java
index 839c19b..38e9fe0 100644
--- a/src/com/android/calculator2/Evaluator.java
+++ b/src/com/android/calculator2/Evaluator.java
@@ -350,7 +350,7 @@
return new InitialResult(R.string.timeout);
}
int precOffset = INIT_PREC;
- String initResult = res.val.toString(precOffset);
+ String initResult = res.toString(precOffset);
int msd = getMsdIndexOf(initResult);
if (BoundedRational.asBigInteger(res.ratVal) == null
&& msd == INVALID_MSD) {
@@ -364,7 +364,7 @@
final int newPrecOffset = initDisplayOffset + EXTRA_DIGITS;
if (newPrecOffset > precOffset) {
precOffset = newPrecOffset;
- initResult = res.val.toString(precOffset);
+ initResult = res.toString(precOffset);
}
return new InitialResult(res.val, res.ratVal,
initResult, precOffset, initDisplayOffset);
@@ -905,6 +905,13 @@
}
/**
+ * Is a reevaluation still in progress?
+ */
+ public boolean reevaluationInProgress() {
+ return mCurrentReevaluator != null;
+ }
+
+ /**
* Cancel all current background tasks.
* @param quiet suppress cancellation message
* @return true if we cancelled an initial evaluation
diff --git a/tests/src/com/android/calculator2/BRTest.java b/tests/src/com/android/calculator2/BRTest.java
index 68214d0..f287a9e 100644
--- a/tests/src/com/android/calculator2/BRTest.java
+++ b/tests/src/com/android/calculator2/BRTest.java
@@ -128,7 +128,10 @@
public void testBR() {
BoundedRational b = new BoundedRational(4,-6);
check(b.toString().equals("4/-6"), "toString(4/-6)");
- check(b.toNiceString().equals("-2/3"),"toNiceString(4/-6)");
+ check(b.toNiceString().equals("-2/3"), "toNiceString(4/-6)");
+ check(b.toString(1).equals("-0.6"), "(4/-6).toString(1)");
+ check(BR_15.toString(0).equals("15."), "15.toString(1)");
+ check(BR_0.toString(2).equals("0.00"), "0.toString(2)");
checkEq(BR_0, CR.valueOf(0), "0");
checkEq(BR_390, CR.valueOf(390), "390");
checkEq(BR_15, CR.valueOf(15), "15");