Make Spacer as extended Key class

Bug: 5275003
Change-Id: I809a8ca363ba72b22ac5cfd926414990f7e8467c
diff --git a/java/res/values/attrs.xml b/java/res/values/attrs.xml
index 3d6428d..a456b22 100644
--- a/java/res/values/attrs.xml
+++ b/java/res/values/attrs.xml
@@ -150,8 +150,8 @@
              area between the nearest key on the left hand side and the right edge of the keyboard.
              -->
         <attr name="keyWidth" format="dimension|fraction|enum">
-            <enum name="fillRight" value="0" />
-            <enum name="fillBoth" value="-1" />
+            <enum name="fillRight" value="-1" />
+            <enum name="fillBoth" value="-2" />
         </attr>
         <!-- Default height of a row (key height + vertical gap), in pixels or percentage of
              keyboard height. -->
diff --git a/java/res/xml-sw600dp/kbd_phone.xml b/java/res/xml-sw600dp/kbd_phone.xml
index 0331389..303f814 100644
--- a/java/res/xml-sw600dp/kbd_phone.xml
+++ b/java/res/xml-sw600dp/kbd_phone.xml
@@ -105,7 +105,7 @@
         <Key
             latin:keyStyle="nonSpecialBackgroundSpaceKeyStyle"
             latin:keyXPos="15.625%p"
-            latin:keyWidth="18.67%p" />
+            latin:keyWidth="18.50%p" />
         <Key
             latin:keyStyle="numStarKeyStyle"
             latin:keyXPos="38.867%p" />
diff --git a/java/res/xml-sw768dp/kbd_qwerty_row4.xml b/java/res/xml-sw768dp/kbd_qwerty_row4.xml
index 9346111..e35e47d 100644
--- a/java/res/xml-sw768dp/kbd_qwerty_row4.xml
+++ b/java/res/xml-sw768dp/kbd_qwerty_row4.xml
@@ -35,7 +35,7 @@
         </switch>
         <Spacer
             latin:keyXPos="15.157%p"
-            latin:keyWidth="fillRight" />
+            latin:keyWidth="0%p" />
         <switch>
             <case
                 latin:mode="url"
diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java
index 15ec80b..735caae 100644
--- a/java/src/com/android/inputmethod/keyboard/Key.java
+++ b/java/src/com/android/inputmethod/keyboard/Key.java
@@ -115,9 +115,10 @@
     /** Whether this key needs to show the "..." popup hint for special purposes */
     private boolean mNeedsSpecialPopupHint;
 
-    // keyWidth constants
-    private static final int KEYWIDTH_FILL_RIGHT = 0;
-    private static final int KEYWIDTH_FILL_BOTH = -1;
+    // keyWidth enum constants
+    private static final int KEYWIDTH_NOT_ENUM = 0;
+    private static final int KEYWIDTH_FILL_RIGHT = -1;
+    private static final int KEYWIDTH_FILL_BOTH = -2;
 
     private final static int[] KEY_STATE_NORMAL_ON = {
         android.R.attr.state_checkable,
@@ -249,15 +250,17 @@
      */
     public Key(Resources res, KeyboardParams params, KeyboardBuilder.Row row,
             XmlResourceParser parser, KeyStyles keyStyles) {
-
         final TypedArray keyboardAttr = res.obtainAttributes(Xml.asAttributeSet(parser),
                 R.styleable.Keyboard);
         mHeight = (int)KeyboardBuilder.getDimensionOrFraction(keyboardAttr,
                 R.styleable.Keyboard_rowHeight, params.mHeight, row.mRowHeight)
                 - params.mVerticalGap;
-        final float horizontalGap = KeyboardBuilder.getDimensionOrFraction(keyboardAttr,
-                R.styleable.Keyboard_horizontalGap, params.mWidth, params.mHorizontalGap);
+        final float horizontalGap = isSpacer() ? 0
+                : KeyboardBuilder.getDimensionOrFraction(keyboardAttr,
+                        R.styleable.Keyboard_horizontalGap, params.mWidth, params.mHorizontalGap);
         mVerticalGap = params.mVerticalGap;
+        final int widthType = KeyboardBuilder.getEnumValue(keyboardAttr,
+                R.styleable.Keyboard_keyWidth, KEYWIDTH_NOT_ENUM);
         float keyWidth = KeyboardBuilder.getDimensionOrFraction(keyboardAttr,
                 R.styleable.Keyboard_keyWidth, params.mWidth, row.mDefaultKeyWidth);
         keyboardAttr.recycle();
@@ -288,11 +291,11 @@
                 keyXPos = x;
             }
         }
-        if (keyWidth == KEYWIDTH_FILL_RIGHT) {
+        if (widthType == KEYWIDTH_FILL_RIGHT) {
             // If keyWidth is zero, the actual key width will be determined to fill out the
             // area up to the right edge of the keyboard.
             keyWidth = keyboardWidth - keyXPos;
-        } else if (keyWidth <= KEYWIDTH_FILL_BOTH) {
+        } else if (widthType == KEYWIDTH_FILL_BOTH) {
             // If keyWidth is negative, the actual key width will be determined to fill out the
             // area between the nearest key on the left hand side and the right edge of the
             // keyboard.
@@ -367,6 +370,10 @@
         mEdgeFlags |= flags;
     }
 
+    public boolean isSpacer() {
+        return false;
+    }
+
     public Typeface selectTypeface(Typeface defaultTypeface) {
         // TODO: Handle "bold" here too?
         if ((mLabelOption & LABEL_OPTION_FONT_NORMAL) != 0) {
@@ -559,4 +566,16 @@
         }
         return states;
     }
+
+    public static class Spacer extends Key {
+        public Spacer(Resources res, KeyboardParams params, KeyboardBuilder.Row row,
+                XmlResourceParser parser, KeyStyles keyStyles) {
+            super(res, params, row, parser, keyStyles);
+        }
+
+        @Override
+        public boolean isSpacer() {
+            return true;
+        }
+    }
 }
diff --git a/java/src/com/android/inputmethod/keyboard/KeyboardView.java b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
index f45fd30..acb76cc 100644
--- a/java/src/com/android/inputmethod/keyboard/KeyboardView.java
+++ b/java/src/com/android/inputmethod/keyboard/KeyboardView.java
@@ -510,24 +510,26 @@
             Paint paint, KeyDrawParams params, boolean isManualTemporaryUpperCase) {
         final boolean debugShowAlign = LatinImeLogger.sVISUALDEBUG;
         // Draw key background.
-        final int bgWidth = key.mWidth - key.mVisualInsetsLeft - key.mVisualInsetsRight
-                + params.mPadding.left + params.mPadding.right;
-        final int bgHeight = key.mHeight + params.mPadding.top + params.mPadding.bottom;
-        final int bgX = -params.mPadding.left;
-        final int bgY = -params.mPadding.top;
-        final int[] drawableState = key.getCurrentDrawableState();
-        final Drawable background = params.mKeyBackground;
-        background.setState(drawableState);
-        final Rect bounds = background.getBounds();
-        if (bgWidth != bounds.right || bgHeight != bounds.bottom) {
-            background.setBounds(0, 0, bgWidth, bgHeight);
+        if (!key.isSpacer()) {
+            final int bgWidth = key.mWidth - key.mVisualInsetsLeft - key.mVisualInsetsRight
+                    + params.mPadding.left + params.mPadding.right;
+            final int bgHeight = key.mHeight + params.mPadding.top + params.mPadding.bottom;
+            final int bgX = -params.mPadding.left;
+            final int bgY = -params.mPadding.top;
+            final int[] drawableState = key.getCurrentDrawableState();
+            final Drawable background = params.mKeyBackground;
+            background.setState(drawableState);
+            final Rect bounds = background.getBounds();
+            if (bgWidth != bounds.right || bgHeight != bounds.bottom) {
+                background.setBounds(0, 0, bgWidth, bgHeight);
+            }
+            canvas.translate(bgX, bgY);
+            background.draw(canvas);
+            if (debugShowAlign) {
+                drawRectangle(canvas, 0, 0, bgWidth, bgHeight, 0x80c00000, new Paint());
+            }
+            canvas.translate(-bgX, -bgY);
         }
-        canvas.translate(bgX, bgY);
-        background.draw(canvas);
-        if (debugShowAlign) {
-            drawRectangle(canvas, 0, 0, bgWidth, bgHeight, 0x80c00000, new Paint());
-        }
-        canvas.translate(-bgX, -bgY);
 
         // Draw key top visuals.
         final int keyWidth = key.mWidth - key.mVisualInsetsLeft - key.mVisualInsetsRight;
diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
index 7190b05..a82bcbe 100644
--- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
+++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
@@ -122,6 +122,7 @@
                 int count = 0;
                 for (int i = 0; i < keys.size(); i++) {
                     final Key key = keys.get(i);
+                    if (key.isSpacer()) continue;
                     if (key.squaredDistanceToEdge(centerX, centerY) < threshold)
                         indices[count++] = i;
                 }
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
index fb1c061..e39548e 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
@@ -394,12 +394,11 @@
         if (skip) {
             checkEndTag(TAG_KEY, parser);
         } else {
-            Key key = new Key(mResources, mParams, row, parser, mKeyStyles);
+            final Key key = new Key(mResources, mParams, row, parser, mKeyStyles);
             if (DEBUG) Log.d(TAG, String.format("<%s%s keyLabel=%s code=%d moreKeys=%s />",
                     TAG_KEY, (key.isEnabled() ? "" : " disabled"), key.mLabel, key.mCode,
                     Arrays.toString(key.mMoreKeys)));
             checkEndTag(TAG_KEY, parser);
-            mParams.onAddKey(key);
             endKey(key);
         }
     }
@@ -409,27 +408,10 @@
         if (skip) {
             checkEndTag(TAG_SPACER, parser);
         } else {
+            final Key.Spacer spacer = new Key.Spacer(mResources, mParams, row, parser, mKeyStyles);
             if (DEBUG) Log.d(TAG, String.format("<%s />", TAG_SPACER));
-            final TypedArray keyboardAttr = mResources.obtainAttributes(Xml.asAttributeSet(parser),
-                    R.styleable.Keyboard);
-            if (keyboardAttr.hasValue(R.styleable.Keyboard_horizontalGap))
-                throw new IllegalAttribute(parser, "horizontalGap");
-            final int keyboardWidth = mParams.mWidth;
-            final float keyWidth = getDimensionOrFraction(keyboardAttr,
-                    R.styleable.Keyboard_keyWidth, keyboardWidth, row.mDefaultKeyWidth);
-            keyboardAttr.recycle();
-
-            final TypedArray keyAttr = mResources.obtainAttributes(Xml.asAttributeSet(parser),
-                    R.styleable.Keyboard_Key);
-            float keyXPos = getDimensionOrFraction(keyAttr,
-                    R.styleable.Keyboard_Key_keyXPos, keyboardWidth, row.mCurrentX);
-            if (keyXPos < 0) {
-                // If keyXPos is negative, the actual x-coordinate will be display_width + keyXPos.
-                keyXPos += keyboardWidth;
-            }
-
             checkEndTag(TAG_SPACER, parser);
-            setSpacer(keyXPos, keyWidth, row);
+            endKey(spacer);
         }
     }
 
@@ -686,7 +668,7 @@
 
     private void startRow(Row row) {
         row.mCurrentX = 0;
-        setSpacer(row.mCurrentX, mParams.mHorizontalEdgesPadding, row);
+        addEdgeSpace(mParams.mHorizontalEdgesPadding, row);
         mCurrentRow = row;
         mLeftEdge = true;
         mRightEdgeKey = null;
@@ -699,13 +681,14 @@
             mRightEdgeKey.addEdgeFlags(Keyboard.EDGE_RIGHT);
             mRightEdgeKey = null;
         }
-        setSpacer(row.mCurrentX, mParams.mHorizontalEdgesPadding, row);
+        addEdgeSpace(mParams.mHorizontalEdgesPadding, row);
         mCurrentY += mCurrentRow.mRowHeight;
         mCurrentRow = null;
         mTopEdge = false;
     }
 
     private void endKey(Key key) {
+        mParams.onAddKey(key);
         if (mLeftEdge) {
             key.addEdgeFlags(Keyboard.EDGE_LEFT);
             mLeftEdge = false;
@@ -719,8 +702,8 @@
     private void endKeyboard() {
     }
 
-    private void setSpacer(float keyXPos, float width, Row row) {
-        row.mCurrentX = keyXPos + width;
+    private void addEdgeSpace(float width, Row row) {
+        row.mCurrentX += width;
         mLeftEdge = false;
         mRightEdgeKey = null;
     }
@@ -733,9 +716,16 @@
             return a.getFraction(index, base, base, defValue);
         } else if (isDimensionValue(value)) {
             return a.getDimension(index, defValue);
-        } else if (isIntegerValue(value)) {
-            // For enum value.
-            return a.getInt(index, 0);
+        }
+        return defValue;
+    }
+
+    public static int getEnumValue(TypedArray a, int index, int defValue) {
+        final TypedValue value = a.peekValue(index);
+        if (value == null)
+            return defValue;
+        if (isIntegerValue(value)) {
+            return a.getInt(index, defValue);
         }
         return defValue;
     }