Improve accessibility for hardware keyboard mode.

Like a normal edittext, speak out each key as its typed.

Bug: 8590343
Change-Id: I52ff588aad5714d751a008e9d7c0574709a0c7e5
diff --git a/res/values/strings.xml b/res/values/strings.xml
index e94fd37..e11a9a1 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -53,6 +53,8 @@
     <string name="select_year">Select year</string>
     <!-- Accessibility description for the item that is currently selected. -->
     <string name="item_is_selected"><xliff:g id="item" example="2013">%1$s</xliff:g> selected</string>
+    <!-- Accessibility announcement when a number that had been typed in is deleted [CHAR_LIMIT=NONE] -->
+    <string name="deleted_key"><xliff:g id="key" example="4">%1$s</xliff:g> deleted</string>
 
     <!-- DO NOT TRANSLATE -->
     <string name="time_placeholder">--</string>
@@ -66,4 +68,4 @@
 
     <!-- DO NOT TRANSLATE -->
     <string name="day_of_week_label_typeface">sans-serif</string>
-</resources>
\ No newline at end of file
+</resources>
diff --git a/src/com/android/datetimepicker/time/TimePickerDialog.java b/src/com/android/datetimepicker/time/TimePickerDialog.java
index 2a385f7..d5db83b 100644
--- a/src/com/android/datetimepicker/time/TimePickerDialog.java
+++ b/src/com/android/datetimepicker/time/TimePickerDialog.java
@@ -91,6 +91,7 @@
     // For hardware IME input.
     private char mPlaceholderText;
     private String mDoublePlaceholderText;
+    private String mDeletedKeyFormat;
     private boolean mInKbMode;
     private ArrayList<Integer> mTypedTimes;
     private Node mLegalTimesTree;
@@ -275,6 +276,7 @@
 
         // Set up for keyboard mode.
         mDoublePlaceholderText = res.getString(R.string.time_placeholder);
+        mDeletedKeyFormat = res.getString(R.string.deleted_key);
         mPlaceholderText = mDoublePlaceholderText.charAt(0);
         mAmKeyCode = mPmKeyCode = -1;
         generateLegalTimesTree();
@@ -441,7 +443,17 @@
         } else if (keyCode == KeyEvent.KEYCODE_DEL) {
             if (mInKbMode) {
                 if (!mTypedTimes.isEmpty()) {
-                    deleteLastTypedKey();
+                    int deleted = deleteLastTypedKey();
+                    String deletedKeyStr;
+                    if (deleted == getAmOrPmKeyCode(AM)) {
+                        deletedKeyStr = mAmText;
+                    } else if (deleted == getAmOrPmKeyCode(PM)) {
+                        deletedKeyStr = mPmText;
+                    } else {
+                        deletedKeyStr = String.format("%d", getValFromKeyCode(deleted));
+                    }
+                    Utils.tryAccessibilityAnnounce(mTimePicker,
+                            String.format(mDeletedKeyFormat, deletedKeyStr));
                     updateDisplay(true);
                 }
             }
@@ -501,6 +513,8 @@
             return false;
         }
 
+        int val = getValFromKeyCode(keyCode);
+        Utils.tryAccessibilityAnnounce(mTimePicker, String.format("%d", val));
         // Automatically fill in 0's if AM or PM was legally entered.
         if (isTypedTimeFullyLegal()) {
             if (!mIs24HourMode && mTypedTimes.size() <= 3) {
@@ -545,11 +559,12 @@
         }
     }
 
-    private void deleteLastTypedKey() {
-        mTypedTimes.remove(mTypedTimes.size() - 1);
+    private int deleteLastTypedKey() {
+        int deleted = mTypedTimes.remove(mTypedTimes.size() - 1);
         if (!isTypedTimeFullyLegal()) {
             mDoneButton.setEnabled(false);
         }
+        return deleted;
     }
 
     /**
@@ -600,8 +615,10 @@
             String minuteStr = (values[1] == -1)? mDoublePlaceholderText :
                 String.format(minuteFormat, values[1]).replace(' ', mPlaceholderText);
             mHourView.setText(hourStr);
+            mHourSpaceView.setText(hourStr);
             mHourView.setTextColor(mBlack);
             mMinuteView.setText(minuteStr);
+            mMinuteSpaceView.setText(minuteStr);
             mMinuteView.setTextColor(mBlack);
             if (!mIs24HourMode) {
                 updateAmPmDisplay(values[2]);