Support time, date, and datetime keyboard

Bug: 6030364
Change-Id: I2bd4daf264757d8f3fa7c946d10a39c36ccf5905
diff --git a/java/res/values/donottranslate-more-keys.xml b/java/res/values/donottranslate-more-keys.xml
index 40d8117..afce245 100644
--- a/java/res/values/donottranslate-more-keys.xml
+++ b/java/res/values/donottranslate-more-keys.xml
@@ -115,6 +115,7 @@
     <!-- U+207F: "ⁿ" SUPERSCRIPT LATIN SMALL LETTER N
          U+2205: "∅" EMPTY SET -->
     <string name="more_keys_for_symbols_0">&#x207F;,&#x2205;</string>
+    <string name="more_keys_for_am_pm">!fixedColumnOrder!2,!hasLabels!,\@string/label_time_am,\@string/label_time_pm</string>
     <string name="settings_as_more_key">\@icon/settingsKey|\@integer/key_settings</string>
     <string name="keylabel_for_comma">,</string>
     <string name="more_keys_for_comma"></string>
diff --git a/java/res/values/donottranslate.xml b/java/res/values/donottranslate.xml
index 94da946..d6a15de 100644
--- a/java/res/values/donottranslate.xml
+++ b/java/res/values/donottranslate.xml
@@ -58,6 +58,10 @@
     <!-- U+FF0A: "*" FULLWIDTH ASTERISK
          U+FF03: "#" FULLWIDTH NUMBER SIGN -->
     <string name="label_to_phone_symbols_key">&#xFF0A;&#xFF03;</string>
+    <!-- Key label for "ante meridiem" -->
+    <string name="label_time_am">"AM"</string>
+    <!-- Key label for "post meridiem" -->
+    <string name="label_time_pm">"PM"</string>
 
     <!--  Always show the suggestion strip -->
     <string name="prefs_suggestion_visibility_show_value">0</string>
diff --git a/java/res/xml-sw600dp/rows_number_normal.xml b/java/res/xml-sw600dp/rows_number_normal.xml
index 1c38a62..3704c52 100644
--- a/java/res/xml-sw600dp/rows_number_normal.xml
+++ b/java/res/xml-sw600dp/rows_number_normal.xml
@@ -63,10 +63,24 @@
             latin:keyLabel="/"
             latin:keyStyle="numKeyStyle"
             latin:keyWidth="9.25%p" />
-        <Key
-            latin:keyLabel=","
-            latin:keyStyle="numKeyStyle"
-            latin:keyWidth="9.25%p" />
+        <switch>
+            <case
+                latin:mode="time|datetime"
+            >
+                <Key
+                    latin:keyLabel=","
+                    latin:keyLabelFlags="hasPopupHint"
+                    latin:moreKeys="@string/more_keys_for_am_pm"
+                    latin:keyStyle="numKeyStyle"
+                    latin:keyWidth="9.25%p" />
+            </case>
+            <default>
+                <Key
+                    latin:keyLabel=","
+                    latin:keyStyle="numKeyStyle"
+                    latin:keyWidth="9.25%p" />
+            </default>
+        </switch>
         <Key
             latin:keyLabel="4"
             latin:keyStyle="numKeyStyle"
@@ -94,10 +108,22 @@
             latin:keyLabel=")"
             latin:keyStyle="numKeyStyle"
             latin:keyWidth="9.25%p" />
-        <Key
-            latin:keyLabel="="
-            latin:keyStyle="numKeyStyle"
-            latin:keyWidth="9.25%p" />
+        <switch>
+            <case
+                latin:mode="time|datetime"
+            >
+                <Key
+                    latin:keyLabel=":"
+                    latin:keyStyle="numKeyStyle"
+                    latin:keyWidth="9.25%p" />
+            </case>
+            <default>
+                <Key
+                    latin:keyLabel="="
+                    latin:keyStyle="numKeyStyle"
+                    latin:keyWidth="9.25%p" />
+            </default>
+        </switch>
         <Key
             latin:keyLabel="7"
             latin:keyStyle="numKeyStyle"
diff --git a/java/res/xml-sw768dp/rows_number_normal.xml b/java/res/xml-sw768dp/rows_number_normal.xml
index 60674cd..8bf1a17 100644
--- a/java/res/xml-sw768dp/rows_number_normal.xml
+++ b/java/res/xml-sw768dp/rows_number_normal.xml
@@ -65,10 +65,24 @@
             latin:keyLabel="/"
             latin:keyStyle="numKeyStyle"
             latin:keyWidth="8.047%p" />
-        <Key
-            latin:keyLabel=","
-            latin:keyStyle="numKeyStyle"
-            latin:keyWidth="8.047%p" />
+        <switch>
+            <case
+                latin:mode="time|datetime"
+            >
+                <Key
+                    latin:keyLabel=","
+                    latin:keyLabelFlags="hasPopupHint"
+                    latin:moreKeys="@string/more_keys_for_am_pm"
+                    latin:keyStyle="numKeyStyle"
+                    latin:keyWidth="8.047%p" />
+            </case>
+            <default>
+                <Key
+                    latin:keyLabel=","
+                    latin:keyStyle="numKeyStyle"
+                    latin:keyWidth="8.047%p" />
+            </default>
+        </switch>
         <Key
             latin:keyLabel="4"
             latin:keyStyle="numKeyStyle"
@@ -96,10 +110,22 @@
             latin:keyLabel=")"
             latin:keyStyle="numKeyStyle"
             latin:keyWidth="8.047%p" />
-        <Key
-            latin:keyLabel="="
-            latin:keyStyle="numKeyStyle"
-            latin:keyWidth="8.047%p" />
+        <switch>
+            <case
+                latin:mode="time|datetime"
+            >
+                <Key
+                    latin:keyLabel=":"
+                    latin:keyStyle="numKeyStyle"
+                    latin:keyWidth="8.047%p" />
+            </case>
+            <default>
+                <Key
+                    latin:keyLabel="="
+                    latin:keyStyle="numKeyStyle"
+                    latin:keyWidth="8.047%p" />
+            </default>
+        </switch>
         <Key
             latin:keyLabel="7"
             latin:keyStyle="numKeyStyle"
diff --git a/java/res/xml/key_styles_number.xml b/java/res/xml/key_styles_number.xml
index 01f7aee..3627836 100644
--- a/java/res/xml/key_styles_number.xml
+++ b/java/res/xml/key_styles_number.xml
@@ -41,9 +41,12 @@
         latin:styleName="numberKeyStyle"
         latin:keyLabelFlags="alignLeftOfCenter|hasHintLabel"
         latin:parentStyle="numKeyStyle" />
+    <!-- U+0030: "0" DIGIT ZERO
+         U+002B: "+" PLUS SIGN -->
     <key-style
         latin:styleName="num0KeyStyle"
-        latin:code="48"
+        latin:code="0x0030"
+        latin:altCode="0x002B"
         latin:keyLabel="0 +"
         latin:keyActionFlags="enableLongPress"
         latin:parentStyle="numberKeyStyle" />
@@ -91,10 +94,11 @@
         latin:keyLabel="9"
         latin:keyHintLabel="WXYZ"
         latin:parentStyle="numberKeyStyle" />
-    <!-- U+FF0A: "*" FULLWIDTH ASTERISK -->
+    <!-- U+002A: "*" ASTERISK
+         U+FF0A: "*" FULLWIDTH ASTERISK -->
     <key-style
         latin:styleName="numStarKeyStyle"
-        latin:code="42"
+        latin:code="0x002A"
         latin:keyLabel="&#xFF0A;"
         latin:parentStyle="numKeyStyle" />
     <!-- Only for non-tablet device -->
@@ -108,15 +112,17 @@
         latin:code="@integer/key_switch_alpha_symbol"
         latin:keyLabel="@string/label_to_phone_numeric_key"
         latin:parentStyle="numModeKeyStyle" />
+    <!-- U+002C: "," COMMA -->
     <key-style
         latin:styleName="numPauseKeyStyle"
-        latin:code="44"
+        latin:code="0x002C"
         latin:keyLabel="@string/label_pause_key"
         latin:keyLabelFlags="followKeyHintLabelRatio|autoXScale"
         latin:parentStyle="numKeyBaseStyle" />
+    <!-- U+003B: ";" SEMICOLON -->
     <key-style
         latin:styleName="numWaitKeyStyle"
-        latin:code="59"
+        latin:code="0x003B"
         latin:keyLabel="@string/label_wait_key"
         latin:keyLabelFlags="followKeyHintLabelRatio|autoXScale"
         latin:parentStyle="numKeyBaseStyle" />
diff --git a/java/res/xml/rows_number_normal.xml b/java/res/xml/rows_number_normal.xml
index b581fb5..91b1fe9 100644
--- a/java/res/xml/rows_number_normal.xml
+++ b/java/res/xml/rows_number_normal.xml
@@ -46,10 +46,32 @@
         <Key
             latin:keyLabel="6"
             latin:keyStyle="numKeyStyle" />
-        <Key
-            latin:keyLabel=","
-            latin:keyStyle="numFunctionalKeyStyle"
-            latin:keyWidth="fillRight" />
+        <switch>
+            <case
+                latin:mode="date"
+            >
+                <Key
+                    latin:keyLabel="."
+                    latin:keyStyle="numFunctionalKeyStyle"
+                    latin:keyWidth="fillRight" />
+            </case>
+            <case
+                latin:mode="time|datetime"
+            >
+                <Key
+                    latin:keyLabel="."
+                    latin:keyLabelFlags="hasPopupHint"
+                    latin:moreKeys="@string/more_keys_for_am_pm"
+                    latin:keyStyle="numFunctionalKeyStyle"
+                    latin:keyWidth="fillRight" />
+            </case>
+            <default>
+                <Key
+                    latin:keyLabel=","
+                    latin:keyStyle="numFunctionalKeyStyle"
+                    latin:keyWidth="fillRight" />
+            </default>
+        </switch>
     </Row>
     <Row>
         <Key
@@ -71,9 +93,39 @@
         <Key
             latin:keyLabel="0"
             latin:keyStyle="numKeyStyle" />
-        <Key
-            latin:keyLabel="."
-            latin:keyStyle="numKeyStyle" />
+        <switch>
+            <case
+                latin:mode="date"
+            >
+                <Key
+                    latin:keyLabel="/"
+                    latin:keyStyle="numKeyStyle" />
+            </case>
+            <case
+                latin:mode="time"
+            >
+                <Key
+                    latin:keyLabel=":"
+                    latin:keyStyle="numKeyStyle" />
+            </case>
+            <case
+                latin:mode="datetime"
+            >
+                <!-- U+002F: "/" SOLIDUS
+                     U+003A: ":" COLON -->
+                <Key
+                    latin:code="0x002F"
+                    latin:altCode="0x003A"
+                    latin:keyLabel="/ :"
+                    latin:keyActionFlags="enableLongPress"
+                    latin:keyStyle="numKeyStyle" />
+            </case>
+            <default>
+                <Key
+                    latin:keyLabel="."
+                    latin:keyStyle="numKeyStyle" />
+            </default>
+        </switch>
         <Key
             latin:keyStyle="enterKeyStyle"
             latin:keyWidth="fillRight" />
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index 30ed59e..c6cdf79 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -85,8 +85,6 @@
     public static final int CODE_CLOSING_SQUARE_BRACKET = ']';
     public static final int CODE_CLOSING_CURLY_BRACKET = '}';
     public static final int CODE_CLOSING_ANGLE_BRACKET = '>';
-    public static final int CODE_DIGIT0 = '0';
-    public static final int CODE_PLUS = '+';
     private static final int MINIMUM_LETTER_CODE = CODE_TAB;
 
     /** Special keys code. Must be negative.
@@ -185,18 +183,11 @@
     }
 
     // TODO: Remove this method.
-    public boolean isShiftLocked() {
-        return mId.isAlphabetShiftLockedKeyboard();
-    }
-
-    // TODO: Remove this method.
     public boolean isShiftedOrShiftLocked() {
-        return mId.isAlphabetShiftedOrShiftLockedKeyboard();
-    }
-
-    // TODO: Remove this method.
-    public boolean isManualShifted() {
-        return mId.isAlphabetManualShiftedKeyboard();
+        // Alphabet mode have unshifted, manual shifted, automatic shifted, shift locked, and
+        // shift lock shifted element. So that unshifed element is the only one that is NOT in
+        // shifted or shift locked state.
+        return mId.isAlphabetKeyboard() && mId.mElementId != KeyboardId.ELEMENT_ALPHABET;
     }
 
     public static boolean isLetterCode(int code) {
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardId.java b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
index ed4a89e..f575296 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardId.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardId.java
@@ -36,6 +36,9 @@
     public static final int MODE_IM = 3;
     public static final int MODE_PHONE = 4;
     public static final int MODE_NUMBER = 5;
+    public static final int MODE_DATE = 6;
+    public static final int MODE_TIME = 7;
+    public static final int MODE_DATETIME = 8;
 
     public static final int ELEMENT_ALPHABET = 0;
     public static final int ELEMENT_ALPHABET_MANUAL_SHIFTED = 1;
@@ -123,31 +126,6 @@
         return mElementId < ELEMENT_SYMBOLS;
     }
 
-    public boolean isAlphabetShiftLockedKeyboard() {
-        return mElementId == ELEMENT_ALPHABET_SHIFT_LOCKED
-                || mElementId == ELEMENT_ALPHABET_SHIFT_LOCK_SHIFTED;
-    }
-
-    public boolean isAlphabetShiftedOrShiftLockedKeyboard() {
-        return isAlphabetKeyboard() && mElementId != ELEMENT_ALPHABET;
-    }
-
-    public boolean isAlphabetManualShiftedKeyboard() {
-        return mElementId == ELEMENT_ALPHABET_MANUAL_SHIFTED;
-    }
-
-    public boolean isSymbolsKeyboard() {
-        return mElementId == ELEMENT_SYMBOLS || mElementId == ELEMENT_SYMBOLS_SHIFTED;
-    }
-
-    public boolean isPhoneKeyboard() {
-        return mElementId == ELEMENT_PHONE || mElementId == ELEMENT_PHONE_SYMBOLS;
-    }
-
-    public boolean isPhoneShiftKeyboard() {
-        return mElementId == ELEMENT_PHONE_SYMBOLS;
-    }
-
     public boolean navigateNext() {
         return EditorInfoCompatUtils.hasFlagNavigateNext(mEditorInfo.imeOptions);
     }
@@ -242,6 +220,9 @@
         case MODE_IM: return "im";
         case MODE_PHONE: return "phone";
         case MODE_NUMBER: return "number";
+        case MODE_DATE: return "date";
+        case MODE_TIME: return "time";
+        case MODE_DATETIME: return "datetime";
         default: return null;
         }
     }
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java
index 6e62f74..ee882ed 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardSet.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardSet.java
@@ -131,6 +131,9 @@
             }
             break;
         case KeyboardId.MODE_NUMBER:
+        case KeyboardId.MODE_DATE:
+        case KeyboardId.MODE_TIME:
+        case KeyboardId.MODE_DATETIME:
             keyboardSetElementId = KeyboardId.ELEMENT_NUMBER;
             break;
         default:
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index d65253e..78e0ee2 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -849,7 +849,7 @@
         final KeyPreviewDrawParams params = mKeyPreviewDrawParams;
         final int keyDrawX = key.mX + key.mVisualInsetsLeft;
         final int keyDrawWidth = key.mWidth - key.mVisualInsetsLeft - key.mVisualInsetsRight;
-        // What we show as preview should match what we show on key top in onBufferDraw(). 
+        // What we show as preview should match what we show on a key top in onBufferDraw().
         if (key.mLabel != null) {
             // TODO Should take care of temporaryShiftLabel here.
             previewText.setCompoundDrawables(null, null, null, null);
diff --git a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
index 4329595..89dad7b 100644
--- a/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/LatinKeyboardView.java
@@ -481,11 +481,10 @@
      */
     protected boolean onLongPress(Key parentKey, PointerTracker tracker) {
         final int primaryCode = parentKey.mCode;
-        final Keyboard keyboard = getKeyboard();
-        if (primaryCode == Keyboard.CODE_DIGIT0 && keyboard.mId.isPhoneKeyboard()) {
+        if (parentKey.mAltCode != Keyboard.CODE_UNSPECIFIED) {
+            // Long press on a key that has altCode defined.
             tracker.onLongPressed();
-            // Long pressing on 0 in phone number keypad gives you a '+'.
-            invokeCodeInput(Keyboard.CODE_PLUS);
+            invokeCodeInput(parentKey.mAltCode);
             invokeReleaseKey(primaryCode);
             KeyboardSwitcher.getInstance().hapticAndAudioFeedback(primaryCode);
             return true;
diff --git a/java/src/com/android/inputmethod/latin/Utils.java b/java/src/com/android/inputmethod/latin/Utils.java
index 6d63e95..47ea9ee 100644
--- a/java/src/com/android/inputmethod/latin/Utils.java
+++ b/java/src/com/android/inputmethod/latin/Utils.java
@@ -563,8 +563,16 @@
 
         switch (inputType & InputType.TYPE_MASK_CLASS) {
         case InputType.TYPE_CLASS_NUMBER:
-        case InputType.TYPE_CLASS_DATETIME:
             return KeyboardId.MODE_NUMBER;
+        case InputType.TYPE_CLASS_DATETIME:
+            switch (variation) {
+            case InputType.TYPE_DATETIME_VARIATION_DATE:
+                return KeyboardId.MODE_DATE;
+            case InputType.TYPE_DATETIME_VARIATION_TIME:
+                return KeyboardId.MODE_TIME;
+            default: // InputType.TYPE_DATETIME_VARIATION_NORMAL
+                return KeyboardId.MODE_DATETIME;
+            }
         case InputType.TYPE_CLASS_PHONE:
             return KeyboardId.MODE_PHONE;
         case InputType.TYPE_CLASS_TEXT: