Make the Calculator edit text field speak the correctly mathematical content.

Previously: 7x9 would be read as "7EX9" when you really want
"7 multiplied by 9"

Change-Id: I6fd3c1e3d0a40ca8700c10227edbdb445dbb7743
diff --git a/Android.mk b/Android.mk
index 4e4f40e..90f5b5f 100644
--- a/Android.mk
+++ b/Android.mk
@@ -19,7 +19,7 @@
 
 LOCAL_MODULE_TAGS := optional
 
-LOCAL_STATIC_JAVA_LIBRARIES := libarity android-support-v4
+LOCAL_STATIC_JAVA_LIBRARIES := libarity android-support-v4 guava
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 297a244..958a6c4 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -114,4 +114,68 @@
     <string name="eDesc">Euler\'s number</string>
     <string name="piDesc">pi</string>
     <string name="equalDesc">equals</string>
+
+    <!--Content descriptions for accessibility used as keys when determining which mathematical
+    concept description to speak when accessibility features are enabled. Order of the array is
+    important. -->
+    <string-array name="operators" translatable="false">
+        <item>(</item>
+        <item>)</item>
+        <item>!</item>
+        <item>ln</item>
+        <item>log</item>
+        <item>\u221a</item>
+        <item>\u00f7</item>
+        <item>\u00d7</item>
+        <item>+</item>
+        <item>\u2212</item>
+        <item>.</item>
+        <item>^</item>
+        <item>tan</item>
+        <item>sin</item>
+        <item>cos</item>
+        <item>\u03c0</item>
+        <item>=</item>
+    </string-array>
+
+    <!--Content descriptions for accessibility. These strings will be read aloud to users who
+     are using the calculator with accessibility features enabled and hover over the edit text
+     field. These should reflect the mathematical concept instead of a direct representation of
+     what is shown in the text field. Order of the array is important.-->
+    <string-array name="operatorDescs">
+        <!-- Description for mathematical ( [CHAR LIMIT=200]-->
+        <item>left parenthesis</item>
+        <!-- Description for mathematical ) [CHAR LIMIT=200]-->
+        <item>right parenthesis</item>
+        <!-- Description for mathematical ! (factorial) function [CHAR LIMIT=200]-->
+        <item>factorial</item>
+        <!-- Description for mathematical ln [CHAR LIMIT=200]-->
+        <item>natural logarithm</item>
+        <!-- Description for mathematical log [CHAR LIMIT=200]-->
+        <item>logarithm</item>
+        <!-- Description for mathematical square root [CHAR LIMIT=200]-->
+        <item>square root</item>
+        <!-- Description for mathematical / [CHAR LIMIT=200]-->
+        <item>divided by</item>
+        <!-- Description for mathematical x [CHAR LIMIT=200]-->
+        <item>multiplied by</item>
+        <!-- Description for mathematical + [CHAR LIMIT=200]-->
+        <item>plus</item>
+        <!-- Description for mathematical - [CHAR LIMIT=200]-->
+        <item>minus</item>
+        <!-- Description for mathematical . [CHAR LIMIT=200]-->
+        <item>point</item>
+        <!-- Description for mathematical ^ [CHAR LIMIT=200]-->
+        <item>power</item>
+        <!-- Description for mathematical TAN [CHAR LIMIT=200]-->
+        <item>tangent</item>
+        <!-- Description for mathematical SIN [CHAR LIMIT=200]-->
+        <item>sine</item>
+        <!-- Description for mathematical COS [CHAR LIMIT=200]-->
+        <item>cosine</item>
+        <!-- Description for mathematical PI [CHAR LIMIT=200]-->
+        <item>pi</item>
+        <!-- Description for mathematical = [CHAR LIMIT=200]-->
+        <item>equals</item>
+    </string-array>
 </resources>
diff --git a/src/com/android/calculator2/CalculatorEditText.java b/src/com/android/calculator2/CalculatorEditText.java
index 170e116..2135b38 100644
--- a/src/com/android/calculator2/CalculatorEditText.java
+++ b/src/com/android/calculator2/CalculatorEditText.java
@@ -30,9 +30,13 @@
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.MotionEvent;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.EditText;
 import android.widget.Toast;
 
+import com.google.common.collect.ImmutableMap;
+
 public class CalculatorEditText extends EditText {
 
     private static final String LOG_TAG = "Calculator2";
@@ -40,6 +44,8 @@
     private static final int COPY = 1;
     private static final int PASTE = 2;
     private String[] mMenuItemsStrings;
+    private ImmutableMap<String, String> sReplacementTable;
+    private String[] sOperators;
 
     public CalculatorEditText(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -62,6 +68,58 @@
         return true;
     }
 
+    @Override
+    public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
+        super.onInitializeAccessibilityEvent(event);
+        String mathText = mathParse(getText().toString());
+        // Parse the string into something more "mathematical" sounding.
+        if (!TextUtils.isEmpty(mathText)) {
+            event.getText().clear();
+            event.getText().add(mathText);
+            setContentDescription(mathText);
+        }
+    }
+
+    @Override
+    public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+        super.onInitializeAccessibilityNodeInfo(info);
+        info.setText(mathParse(getText().toString()));
+    }
+
+    @Override
+    public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+        // Do nothing.
+    }
+
+    private String mathParse(String plainText) {
+        String parsedText = plainText;
+        if (!TextUtils.isEmpty(parsedText)) {
+            // Initialize replacement table.
+            initializeReplacementTable();
+            for (String operator : sOperators) {
+                if (sReplacementTable.containsKey(operator)) {
+                    parsedText = parsedText.replace(operator, sReplacementTable.get(operator));
+                }
+            }
+        }
+        return parsedText;
+    }
+
+    private synchronized void initializeReplacementTable() {
+        if (sReplacementTable == null) {
+            ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
+            Resources res = getContext().getResources();
+            sOperators = res.getStringArray(R.array.operators);
+            String[] descs = res.getStringArray(R.array.operatorDescs);
+            int pos = 0;
+            for (String key : sOperators) {
+                builder.put(key, descs[pos]);
+                pos++;
+            }
+            sReplacementTable = builder.build();
+        }
+    }
+
     private class MenuHandler implements MenuItem.OnMenuItemClickListener {
         public boolean onMenuItemClick(MenuItem item) {
             return onTextContextMenuItem(item.getTitle());