Loading src/com/android/calculator2/Calculator.java +13 −14 Original line number Diff line number Diff line Loading @@ -14,8 +14,6 @@ * limitations under the License. */ // TODO: Better indication of when the result is known to be exact. // TODO: Check and possibly fix accessability issues. // TODO: Copy & more general paste in formula? Note that this requires // great care: Currently the text version of a displayed formula // is not directly useful for re-evaluating the formula later, since Loading Loading @@ -44,8 +42,10 @@ import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v4.view.ViewPager; import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.style.ForegroundColorSpan; import android.text.TextUtils; import android.util.Property; import android.view.KeyCharacterMap; import android.view.KeyEvent; Loading Loading @@ -210,9 +210,13 @@ public class Calculator extends Activity private View mCurrentButton; private Animator mCurrentAnimator; private String mUnprocessedChars = null; // Characters that were recently entered // at the end of the display that have not yet // Characters that were recently entered at the end of the display that have not yet // been added to the underlying expression. private String mUnprocessedChars = null; // Color to highlight unprocessed characters from physical keyboard. // TODO: should probably match this to the error color? private ForegroundColorSpan mUnprocessedColorSpan = new ForegroundColorSpan(Color.RED); @Override protected void onCreate(Bundle savedInstanceState) { Loading Loading @@ -536,18 +540,13 @@ public class Calculator extends Activity } void redisplayFormula() { String formula = mEvaluator.getExpr().toString(this); SpannableStringBuilder formula = mEvaluator.getExpr().toSpannableStringBuilder(this); if (mUnprocessedChars != null) { // Add and highlight characters we couldn't process. SpannableString formatted = new SpannableString(formula + mUnprocessedChars); // TODO: should probably match this to the error color. formatted.setSpan(new ForegroundColorSpan(Color.RED), formula.length(), formatted.length(), formula.append(mUnprocessedChars, mUnprocessedColorSpan, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); mFormulaText.changeTextTo(formatted); } else { mFormulaText.changeTextTo(formula); } mFormulaText.changeTextTo(formula); } @Override Loading src/com/android/calculator2/CalculatorExpr.java +33 −12 Original line number Diff line number Diff line Loading @@ -21,6 +21,11 @@ import com.hp.creals.CR; import com.hp.creals.UnaryCRFunction; import android.content.Context; import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.style.TtsSpan; import android.text.style.TtsSpan.TextBuilder; import android.util.Log; import java.math.BigInteger; Loading @@ -46,11 +51,19 @@ class CalculatorExpr { private static abstract class Token { abstract TokenKind kind(); /** * Write kind as Byte followed by data needed by subclass constructor. */ abstract void write(DataOutput out) throws IOException; // Implementation writes kind as Byte followed by // data read by constructor. abstract String toString(Context context); // We need the context to convert button ids to strings. /** * Return a textual representation of the token. * The result is suitable for either display as part od the formula or TalkBack use. * It may be a SpannableString that includes added TalkBack information. * @param context context used for converting button ids to strings */ abstract CharSequence toCharSequence(Context context); } // An operator token Loading @@ -68,9 +81,17 @@ class CalculatorExpr { out.writeInt(mId); } @Override public String toString(Context context) { public CharSequence toCharSequence(Context context) { String desc = KeyMaps.toDescriptiveString(context, mId); if (desc != null) { SpannableString result = new SpannableString(KeyMaps.toString(context, mId)); Object descSpan = new TtsSpan.TextBuilder(desc).build(); result.setSpan(descSpan, 0, result.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); return result; } else { return KeyMaps.toString(context, mId); } } @Override TokenKind kind() { return TokenKind.OPERATOR; } } Loading Loading @@ -193,7 +214,7 @@ class CalculatorExpr { } @Override String toString(Context context) { CharSequence toCharSequence(Context context) { return toString(); } Loading Loading @@ -323,7 +344,7 @@ class CalculatorExpr { } } @Override String toString(Context context) { CharSequence toCharSequence(Context context) { return KeyMaps.translateResult(mShortRep); } @Override Loading Loading @@ -1019,11 +1040,11 @@ class CalculatorExpr { } // Produce a string representation of the expression itself String toString(Context context) { StringBuilder sb = new StringBuilder(); SpannableStringBuilder toSpannableStringBuilder(Context context) { SpannableStringBuilder ssb = new SpannableStringBuilder(); for (Token t: mExpr) { sb.append(t.toString(context)); ssb.append(t.toCharSequence(context)); } return sb.toString(); return ssb; } } src/com/android/calculator2/CalculatorText.java +15 −4 Original line number Diff line number Diff line Loading @@ -224,11 +224,22 @@ public class CalculatorText extends AlignedTextView implements View.OnLongClickL * Otherwise, e.g. after deletion, announce the entire new text. */ public void changeTextTo(CharSequence newText) { CharSequence oldText = getText(); final CharSequence oldText = getText(); if (startsWith(newText, oldText)) { int newLen = newText.length(); int oldLen = oldText.length(); if (oldLen != newLen) { final int newLen = newText.length(); final int oldLen = oldText.length(); if (newLen == oldLen + 1) { // The algorithm for pronouncing a single character doesn't seem // to respect our hints. Don't give it the choice. final char c = newText.charAt(oldLen); final int id = KeyMaps.keyForChar(c); final String descr = KeyMaps.toDescriptiveString(getContext(), id); if (descr != null) { announceForAccessibility(descr); } else { announceForAccessibility(String.valueOf(c)); } } else if (newLen > oldLen) { announceForAccessibility(newText.subSequence(oldLen, newLen)); } } else { Loading src/com/android/calculator2/KeyMaps.java +51 −0 Original line number Diff line number Diff line Loading @@ -114,6 +114,57 @@ public class KeyMaps { } } /** * Map key id to corresponding (internationalized) descriptive string that can be used * to correctly read back a formula. * Only used for operators and individual characters; not used inside constants. * Returns null when we don't need a descriptive string. * Pure function. */ public static String toDescriptiveString(Context context, int id) { switch(id) { case R.id.op_fact: return context.getString(R.string.desc_op_fact); case R.id.fun_sin: return context.getString(R.string.desc_fun_sin) + " " + context.getString(R.string.desc_lparen); case R.id.fun_cos: return context.getString(R.string.desc_fun_cos) + " " + context.getString(R.string.desc_lparen); case R.id.fun_tan: return context.getString(R.string.desc_fun_tan) + " " + context.getString(R.string.desc_lparen); case R.id.fun_arcsin: return context.getString(R.string.desc_fun_arcsin) + " " + context.getString(R.string.desc_lparen); case R.id.fun_arccos: return context.getString(R.string.desc_fun_arccos) + " " + context.getString(R.string.desc_lparen); case R.id.fun_arctan: return context.getString(R.string.desc_fun_arctan) + " " + context.getString(R.string.desc_lparen); case R.id.fun_ln: return context.getString(R.string.desc_fun_ln) + " " + context.getString(R.string.desc_lparen); case R.id.fun_log: return context.getString(R.string.desc_fun_log) + " " + context.getString(R.string.desc_lparen); case R.id.fun_exp: return context.getString(R.string.desc_fun_exp) + " " + context.getString(R.string.desc_lparen); case R.id.lparen: return context.getString(R.string.desc_lparen); case R.id.rparen: return context.getString(R.string.desc_rparen); case R.id.op_pow: return context.getString(R.string.desc_op_pow); case R.id.dec_point: return context.getString(R.string.desc_dec_point); default: return null; } } /** * Does a button id correspond to a binary operator? * Pure function. Loading Loading
src/com/android/calculator2/Calculator.java +13 −14 Original line number Diff line number Diff line Loading @@ -14,8 +14,6 @@ * limitations under the License. */ // TODO: Better indication of when the result is known to be exact. // TODO: Check and possibly fix accessability issues. // TODO: Copy & more general paste in formula? Note that this requires // great care: Currently the text version of a displayed formula // is not directly useful for re-evaluating the formula later, since Loading Loading @@ -44,8 +42,10 @@ import android.os.Bundle; import android.support.annotation.NonNull; import android.support.v4.view.ViewPager; import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.style.ForegroundColorSpan; import android.text.TextUtils; import android.util.Property; import android.view.KeyCharacterMap; import android.view.KeyEvent; Loading Loading @@ -210,9 +210,13 @@ public class Calculator extends Activity private View mCurrentButton; private Animator mCurrentAnimator; private String mUnprocessedChars = null; // Characters that were recently entered // at the end of the display that have not yet // Characters that were recently entered at the end of the display that have not yet // been added to the underlying expression. private String mUnprocessedChars = null; // Color to highlight unprocessed characters from physical keyboard. // TODO: should probably match this to the error color? private ForegroundColorSpan mUnprocessedColorSpan = new ForegroundColorSpan(Color.RED); @Override protected void onCreate(Bundle savedInstanceState) { Loading Loading @@ -536,18 +540,13 @@ public class Calculator extends Activity } void redisplayFormula() { String formula = mEvaluator.getExpr().toString(this); SpannableStringBuilder formula = mEvaluator.getExpr().toSpannableStringBuilder(this); if (mUnprocessedChars != null) { // Add and highlight characters we couldn't process. SpannableString formatted = new SpannableString(formula + mUnprocessedChars); // TODO: should probably match this to the error color. formatted.setSpan(new ForegroundColorSpan(Color.RED), formula.length(), formatted.length(), formula.append(mUnprocessedChars, mUnprocessedColorSpan, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); mFormulaText.changeTextTo(formatted); } else { mFormulaText.changeTextTo(formula); } mFormulaText.changeTextTo(formula); } @Override Loading
src/com/android/calculator2/CalculatorExpr.java +33 −12 Original line number Diff line number Diff line Loading @@ -21,6 +21,11 @@ import com.hp.creals.CR; import com.hp.creals.UnaryCRFunction; import android.content.Context; import android.text.SpannableString; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.style.TtsSpan; import android.text.style.TtsSpan.TextBuilder; import android.util.Log; import java.math.BigInteger; Loading @@ -46,11 +51,19 @@ class CalculatorExpr { private static abstract class Token { abstract TokenKind kind(); /** * Write kind as Byte followed by data needed by subclass constructor. */ abstract void write(DataOutput out) throws IOException; // Implementation writes kind as Byte followed by // data read by constructor. abstract String toString(Context context); // We need the context to convert button ids to strings. /** * Return a textual representation of the token. * The result is suitable for either display as part od the formula or TalkBack use. * It may be a SpannableString that includes added TalkBack information. * @param context context used for converting button ids to strings */ abstract CharSequence toCharSequence(Context context); } // An operator token Loading @@ -68,9 +81,17 @@ class CalculatorExpr { out.writeInt(mId); } @Override public String toString(Context context) { public CharSequence toCharSequence(Context context) { String desc = KeyMaps.toDescriptiveString(context, mId); if (desc != null) { SpannableString result = new SpannableString(KeyMaps.toString(context, mId)); Object descSpan = new TtsSpan.TextBuilder(desc).build(); result.setSpan(descSpan, 0, result.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); return result; } else { return KeyMaps.toString(context, mId); } } @Override TokenKind kind() { return TokenKind.OPERATOR; } } Loading Loading @@ -193,7 +214,7 @@ class CalculatorExpr { } @Override String toString(Context context) { CharSequence toCharSequence(Context context) { return toString(); } Loading Loading @@ -323,7 +344,7 @@ class CalculatorExpr { } } @Override String toString(Context context) { CharSequence toCharSequence(Context context) { return KeyMaps.translateResult(mShortRep); } @Override Loading Loading @@ -1019,11 +1040,11 @@ class CalculatorExpr { } // Produce a string representation of the expression itself String toString(Context context) { StringBuilder sb = new StringBuilder(); SpannableStringBuilder toSpannableStringBuilder(Context context) { SpannableStringBuilder ssb = new SpannableStringBuilder(); for (Token t: mExpr) { sb.append(t.toString(context)); ssb.append(t.toCharSequence(context)); } return sb.toString(); return ssb; } }
src/com/android/calculator2/CalculatorText.java +15 −4 Original line number Diff line number Diff line Loading @@ -224,11 +224,22 @@ public class CalculatorText extends AlignedTextView implements View.OnLongClickL * Otherwise, e.g. after deletion, announce the entire new text. */ public void changeTextTo(CharSequence newText) { CharSequence oldText = getText(); final CharSequence oldText = getText(); if (startsWith(newText, oldText)) { int newLen = newText.length(); int oldLen = oldText.length(); if (oldLen != newLen) { final int newLen = newText.length(); final int oldLen = oldText.length(); if (newLen == oldLen + 1) { // The algorithm for pronouncing a single character doesn't seem // to respect our hints. Don't give it the choice. final char c = newText.charAt(oldLen); final int id = KeyMaps.keyForChar(c); final String descr = KeyMaps.toDescriptiveString(getContext(), id); if (descr != null) { announceForAccessibility(descr); } else { announceForAccessibility(String.valueOf(c)); } } else if (newLen > oldLen) { announceForAccessibility(newText.subSequence(oldLen, newLen)); } } else { Loading
src/com/android/calculator2/KeyMaps.java +51 −0 Original line number Diff line number Diff line Loading @@ -114,6 +114,57 @@ public class KeyMaps { } } /** * Map key id to corresponding (internationalized) descriptive string that can be used * to correctly read back a formula. * Only used for operators and individual characters; not used inside constants. * Returns null when we don't need a descriptive string. * Pure function. */ public static String toDescriptiveString(Context context, int id) { switch(id) { case R.id.op_fact: return context.getString(R.string.desc_op_fact); case R.id.fun_sin: return context.getString(R.string.desc_fun_sin) + " " + context.getString(R.string.desc_lparen); case R.id.fun_cos: return context.getString(R.string.desc_fun_cos) + " " + context.getString(R.string.desc_lparen); case R.id.fun_tan: return context.getString(R.string.desc_fun_tan) + " " + context.getString(R.string.desc_lparen); case R.id.fun_arcsin: return context.getString(R.string.desc_fun_arcsin) + " " + context.getString(R.string.desc_lparen); case R.id.fun_arccos: return context.getString(R.string.desc_fun_arccos) + " " + context.getString(R.string.desc_lparen); case R.id.fun_arctan: return context.getString(R.string.desc_fun_arctan) + " " + context.getString(R.string.desc_lparen); case R.id.fun_ln: return context.getString(R.string.desc_fun_ln) + " " + context.getString(R.string.desc_lparen); case R.id.fun_log: return context.getString(R.string.desc_fun_log) + " " + context.getString(R.string.desc_lparen); case R.id.fun_exp: return context.getString(R.string.desc_fun_exp) + " " + context.getString(R.string.desc_lparen); case R.id.lparen: return context.getString(R.string.desc_lparen); case R.id.rparen: return context.getString(R.string.desc_rparen); case R.id.op_pow: return context.getString(R.string.desc_op_pow); case R.id.dec_point: return context.getString(R.string.desc_dec_point); default: return null; } } /** * Does a button id correspond to a binary operator? * Pure function. Loading