summaryrefslogtreecommitdiffstats
path: root/src/com/android/calculator2/CalculatorResult.java
diff options
context:
space:
mode:
authorHans Boehm <hboehm@google.com>2015-05-18 18:25:41 -0700
committerHans Boehm <hboehm@google.com>2015-05-20 18:32:11 -0700
commit61568a15c8d88d86aba14a7800d0bfb46f22c8ba (patch)
tree6b52a21a4a389a6a563bd94aa31a499e7e84b982 /src/com/android/calculator2/CalculatorResult.java
parentffda52845ca6cca5f72795706988a11f6bcf5b03 (diff)
downloadandroid_packages_apps_ExactCalculator-61568a15c8d88d86aba14a7800d0bfb46f22c8ba.tar.gz
android_packages_apps_ExactCalculator-61568a15c8d88d86aba14a7800d0bfb46f22c8ba.tar.bz2
android_packages_apps_ExactCalculator-61568a15c8d88d86aba14a7800d0bfb46f22c8ba.zip
Prevent scrolling of finite results.
Bug: 20562484 Inhibit scrolling past the last nonzero digit when we can identify it. Increase length of immediate result a bit, to make it closer to the L calculator. On "=", expand less for scrollable results, more for short non-scrollable results. This allows us to use larger fonts for short finite results. Fix up animation logic when displaying result. The old version was never quite right, and became more visibly wrong with variable enlargement. This version is simpler and seems to give much better results. This still does not add ellipsis at the right end of a result. But it is now easily possible to tell whether a result is known finite by attempting to scroll it. That may be good enough. Remove some obsolete TODO entries. Change-Id: I25a842a743e1c27191ca18ac69aa9eef0f0ea9b1
Diffstat (limited to 'src/com/android/calculator2/CalculatorResult.java')
-rw-r--r--src/com/android/calculator2/CalculatorResult.java89
1 files changed, 68 insertions, 21 deletions
diff --git a/src/com/android/calculator2/CalculatorResult.java b/src/com/android/calculator2/CalculatorResult.java
index d14135c..a916c30 100644
--- a/src/com/android/calculator2/CalculatorResult.java
+++ b/src/com/android/calculator2/CalculatorResult.java
@@ -48,7 +48,7 @@ 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 {
- static final int MAX_RIGHT_SCROLL = 100000000;
+ static final int MAX_RIGHT_SCROLL = 10000000;
static final int INVALID = MAX_RIGHT_SCROLL + 10000;
// A larger value is unlikely to avoid running out of space
final OverScroller mScroller;
@@ -71,8 +71,10 @@ public class CalculatorResult extends TextView {
// Large positive values mean the decimal point is scrolled off the
// left of the display. Zero means decimal point is barely displayed
// on the right.
- private int mLastPos; // Position already reflected in display.
- private int mMinPos; // Maximum position before all digits disappear of 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 mMaxPos; // Maximum position before we start displaying the infinite
+ // sequence of trailing zeroes on the right. Pixels.
private Object mWidthLock = new Object();
// Protects the next two fields.
private int mWidthConstraint = -1;
@@ -109,14 +111,14 @@ public class CalculatorResult extends TextView {
// Ignore scrolls of error string, etc.
if (!mScrollable) return true;
mScroller.fling(mCurrentPos, 0, - (int) velocityX, 0 /* horizontal only */,
- mMinPos, MAX_RIGHT_SCROLL, 0, 0);
+ mMinPos, mMaxPos, 0, 0);
ViewCompat.postInvalidateOnAnimation(CalculatorResult.this);
return true;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
- // TODO: Should we be dealing with any edge effects here?
+ int distance = (int)distanceX;
if (!mScroller.isFinished()) {
mCurrentPos = mScroller.getFinalX();
}
@@ -124,9 +126,14 @@ public class CalculatorResult extends TextView {
stopActionMode();
CalculatorResult.this.cancelLongPress();
if (!mScrollable) return true;
+ if (mCurrentPos + distance < mMinPos) {
+ distance = mMinPos - mCurrentPos;
+ } else if (mCurrentPos + distance > mMaxPos) {
+ distance = mMaxPos - mCurrentPos;
+ }
int duration = (int)(e2.getEventTime() - e1.getEventTime());
if (duration < 1 || duration > 100) duration = 10;
- mScroller.startScroll(mCurrentPos, 0, (int)distanceX, 0, (int)duration);
+ mScroller.startScroll(mCurrentPos, 0, distance, 0, (int)duration);
ViewCompat.postInvalidateOnAnimation(CalculatorResult.this);
return true;
}
@@ -177,18 +184,45 @@ public class CalculatorResult extends TextView {
}
}
- // Display a new result, given initial displayed
- // precision and the string representing the whole part of
- // the number to be displayed.
- // We pass the string, instead of just the length, so we have
- // one less place to fix in case we ever decide to
- // correctly use a variable width font.
- void displayResult(int initPrec, String truncatedWholePart) {
+ // Given that the last non-zero digit is at pos, compute the precision we have to ask
+ // ask for to actually get the digit at pos displayed. This is not an identity
+ // function, since we may need to drop digits to the right to make room for the exponent.
+ private int addExpSpace(int lastDigit) {
+ if (lastDigit < getMaxChars() - 1) {
+ // The decimal point will be in view when displaying the rightmost digit.
+ // no exponent needed.
+ // TODO: This will change if we stop scrolling to the left of the decimal
+ // point, which might be desirable in the traditional scientific notation case.
+ return lastDigit;
+ }
+ // When the last digit is displayed, the exponent will look like "e-<lastDigit>".
+ // The length of that string is the extra precision we need.
+ return lastDigit + (int)Math.ceil(Math.log10((double)lastDigit)) + 2;
+ }
+
+ // Display a new result, given initial displayed precision, position of the rightmost
+ // nonzero digit (or Integer.MAX_VALUE if non-terminating), and the string representing
+ // the whole part of the number to be displayed.
+ // We pass the string, instead of just the length, so we have one less place to fix in case
+ // we ever decide to fully handle a variable width font.
+ void displayResult(int initPrec, int leastDigPos, String truncatedWholePart) {
mLastPos = INVALID;
synchronized(mWidthLock) {
mCurrentPos = initPrec * mCharWidth;
}
- mMinPos = - (int) Math.ceil(getPaint().measureText(truncatedWholePart));
+ // Should logically be
+ // mMinPos = - (int) Math.ceil(getPaint().measureText(truncatedWholePart)), but
+ // we eventually transalate to a character position by dividing by mCharWidth.
+ // To avoid rounding issues, we use the analogous computation here.
+ mMinPos = - truncatedWholePart.length() * mCharWidth;
+ if (leastDigPos < MAX_RIGHT_SCROLL) {
+ mMaxPos = Math.min(addExpSpace(leastDigPos) * mCharWidth, MAX_RIGHT_SCROLL);
+ } else {
+ mMaxPos = MAX_RIGHT_SCROLL;
+ }
+ mScrollable = (leastDigPos != (initPrec == -1 ? 0 : initPrec));
+ // We assume that initPrec allows most significant digit to be displayed.
+ // If there is nothing to the right of initPrec, there is no point in scrolling.
redisplay();
}
@@ -212,8 +246,6 @@ public class CalculatorResult extends TextView {
// 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) {
@@ -313,13 +345,16 @@ public class CalculatorResult extends TextView {
return (currentCharPos >= BoundedRational.digitsRequired(rat));
}
- // May be called asynchronously from non-UI thread.
+ /**
+ * Return the maximum number of characters that will fit in the result display.
+ * May be called asynchronously from non-UI thread.
+ */
int getMaxChars() {
- // We only use 2/3 of the available space, since the left 1/3 of the result is not
- // visible when it is shown in large size.
+ // We only use 4/5 of the available space, since at least the left 4/5 of the result
+ // is not visible when it is shown in large size.
int result;
synchronized(mWidthLock) {
- result = 2 * mWidthConstraint / (3 * mCharWidth);
+ result = 4 * mWidthConstraint / (5 * mCharWidth);
// We can apparently finish evaluating before onMeasure in CalculatorText has been
// called, in which case we get 0 or -1 as the width constraint.
}
@@ -331,6 +366,19 @@ public class CalculatorResult extends TextView {
}
}
+ /**
+ * Return the fraction of the available character space occupied by the
+ * current result.
+ * Should be called only with a valid result displayed.
+ */
+ float getOccupancy() {
+ if (mScrollable) {
+ return 1.0f;
+ } else {
+ return (float)getText().length() / getMaxChars();
+ }
+ }
+
int getCurrentCharPos() {
synchronized(mWidthLock) {
return mCurrentPos/mCharWidth;
@@ -359,7 +407,6 @@ public class CalculatorResult extends TextView {
setText(result);
}
mValid = true;
- mScrollable = true;
}
@Override