From f70bcf3d323b13b60c0567c69768ed986647f86a Mon Sep 17 00:00:00 2001
From: "Tadashi G. Takaoka" <takaoka@google.com>
Date: Sun, 9 Feb 2014 23:24:02 +0900
Subject: [PATCH] Refactor Key constructors

This is a followup of I76432556ca.

Change-Id: Ie2c8f7c23352a33db28e89ee8e6ebaba9eb760a3
---
 .../com/android/inputmethod/keyboard/Key.java | 70 +++++++------------
 .../keyboard/MoreKeysKeyboard.java            |  3 +-
 .../keyboard/internal/KeyboardBuilder.java    | 28 ++++++--
 .../keyboard/internal/MoreKeySpec.java        |  8 +++
 .../latin/suggestions/MoreSuggestions.java    |  8 +--
 5 files changed, 60 insertions(+), 57 deletions(-)

diff --git a/java/src/com/android/inputmethod/keyboard/Key.java b/java/src/com/android/inputmethod/keyboard/Key.java
index aade490ac..6f0f75314 100644
--- a/java/src/com/android/inputmethod/keyboard/Key.java
+++ b/java/src/com/android/inputmethod/keyboard/Key.java
@@ -22,13 +22,11 @@ import static com.android.inputmethod.latin.Constants.CODE_SHIFT;
 import static com.android.inputmethod.latin.Constants.CODE_SWITCH_ALPHA_SYMBOL;
 import static com.android.inputmethod.latin.Constants.CODE_UNSPECIFIED;
 
-import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Rect;
 import android.graphics.Typeface;
 import android.graphics.drawable.Drawable;
 import android.text.TextUtils;
-import android.util.Xml;
 
 import com.android.inputmethod.keyboard.internal.KeyDrawParams;
 import com.android.inputmethod.keyboard.internal.KeySpecParser;
@@ -42,9 +40,6 @@ import com.android.inputmethod.latin.Constants;
 import com.android.inputmethod.latin.R;
 import com.android.inputmethod.latin.utils.StringUtils;
 
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
 import java.util.Arrays;
 import java.util.Locale;
 
@@ -188,22 +183,15 @@ public class Key implements Comparable<Key> {
     private boolean mEnabled = true;
 
     /**
-     * This constructor is being used only for keys in more keys keyboard.
+     * Constructor for a key on <code>MoreKeyKeyboard</code>, on <code>MoreSuggestions</code>,
+     * and in a <GridRows/>.
      */
-    public Key(final KeyboardParams params, final MoreKeySpec moreKeySpec, final int x, final int y,
-            final int width, final int height, final int labelFlags) {
-        this(params, moreKeySpec.mLabel, null, moreKeySpec.mIconId, moreKeySpec.mCode,
-                moreKeySpec.mOutputText, x, y, width, height, labelFlags, BACKGROUND_TYPE_NORMAL);
-    }
-
-    /**
-     * This constructor is being used only for key in popup suggestions pane.
-     */
-    public Key(final KeyboardParams params, final String label, final String hintLabel,
-            final int iconId, final int code, final String outputText, final int x, final int y,
-            final int width, final int height, final int labelFlags, final int backgroundType) {
-        mHeight = height - params.mVerticalGap;
-        mWidth = width - params.mHorizontalGap;
+    public Key(final String label, final int iconId, final int code, final String outputText,
+            final String hintLabel, final int labelFlags, final int backgroundType, final int x,
+            final int y, final int width, final int height, final int horizontalGap,
+            final int verticalGap) {
+        mHeight = height - verticalGap;
+        mWidth = width - horizontalGap;
         mHintLabel = hintLabel;
         mLabelFlags = labelFlags;
         mBackgroundType = backgroundType;
@@ -218,7 +206,7 @@ public class Key implements Comparable<Key> {
         mEnabled = (code != CODE_UNSPECIFIED);
         mIconId = iconId;
         // Horizontal gap is divided equally to both sides of the key.
-        mX = x + params.mHorizontalGap / 2;
+        mX = x + horizontalGap / 2;
         mY = y;
         mHitBox.set(x, y, x + width + 1, y + height);
         mKeyVisualAttributes = null;
@@ -227,25 +215,22 @@ public class Key implements Comparable<Key> {
     }
 
     /**
-     * Create a key with the given top-left coordinate and extract its attributes from the XML
-     * parser.
-     * @param res resources associated with the caller's context
+     * Create a key with the given top-left coordinate and extract its attributes from a key
+     * specification string, Key attribute array, key style, and etc.
+     *
+     * @param keySpec the key specification.
+     * @param keyAttr the Key XML attributes array.
+     * @param keyStyle the {@link KeyStyle} of this key.
      * @param params the keyboard building parameters.
      * @param row the row that this key belongs to. row's x-coordinate will be the right edge of
      *        this key.
-     * @param parser the XML parser containing the attributes for this key
-     * @throws XmlPullParserException
      */
-    public Key(final Resources res, final KeyboardParams params, final KeyboardRow row,
-            final XmlPullParser parser) throws XmlPullParserException {
+    public Key(final String keySpec, final TypedArray keyAttr, final KeyStyle style,
+            final KeyboardParams params, final KeyboardRow row) {
         final float horizontalGap = isSpacer() ? 0 : params.mHorizontalGap;
         final int rowHeight = row.getRowHeight();
         mHeight = rowHeight - params.mVerticalGap;
 
-        final TypedArray keyAttr = res.obtainAttributes(Xml.asAttributeSet(parser),
-                R.styleable.Keyboard_Key);
-
-        final KeyStyle style = params.mKeyStyles.getKeyStyle(keyAttr, parser);
         final float keyXPos = row.getKeyX(keyAttr);
         final float keyWidth = row.getKeyWidth(keyAttr, keyXPos);
         final int keyYPos = row.getKeyY();
@@ -315,13 +300,6 @@ public class Key implements Comparable<Key> {
         }
         mActionFlags = actionFlags;
 
-        final String keySpec = style.getString(keyAttr, R.styleable.Keyboard_Key_keySpec);
-        // Note: {@link Spacer} has an empty keySpec.
-        // TODO: Create a Key constructor that parses only key geometries and share it with Spacer.
-        if (TextUtils.isEmpty(keySpec) && !(this instanceof Spacer)) {
-            throw new RuntimeException("Empty keySpec found in " + getClass().getName());
-        }
-
         mIconId = KeySpecParser.getIconId(keySpec);
         final int disabledIconId = KeySpecParser.getIconId(style.getString(keyAttr,
                 R.styleable.Keyboard_Key_keyIconDisabled));
@@ -382,12 +360,11 @@ public class Key implements Comparable<Key> {
         mOptionalAttributes = OptionalAttributes.newInstance(outputText, altCode,
                 disabledIconId, previewIconId, visualInsetsLeft, visualInsetsRight);
         mKeyVisualAttributes = KeyVisualAttributes.newInstance(keyAttr);
-        keyAttr.recycle();
         mHashCode = computeHashCode(this);
     }
 
     /**
-     * Copy constructor.
+     * Copy constructor for DynamicGridKeyboard.GridKey.
      *
      * @param key the original key.
      */
@@ -939,9 +916,9 @@ public class Key implements Comparable<Key> {
     }
 
     public static class Spacer extends Key {
-        public Spacer(final Resources res, final KeyboardParams params, final KeyboardRow row,
-                final XmlPullParser parser) throws XmlPullParserException {
-            super(res, params, row, parser);
+        public Spacer(final TypedArray keyAttr, final KeyStyle keyStyle,
+                final KeyboardParams params, final KeyboardRow row) {
+            super(null /* keySpec */, keyAttr, keyStyle, params, row);
         }
 
         /**
@@ -949,8 +926,9 @@ public class Key implements Comparable<Key> {
          */
         protected Spacer(final KeyboardParams params, final int x, final int y, final int width,
                 final int height) {
-            super(params, null, null, ICON_UNDEFINED, CODE_UNSPECIFIED,
-                    null, x, y, width, height, 0, BACKGROUND_TYPE_EMPTY);
+            super(null /* label */, ICON_UNDEFINED, CODE_UNSPECIFIED, null /* outputText */,
+                    null /* hintLabel */, 0 /* labelFlags */, BACKGROUND_TYPE_EMPTY, x, y, width,
+                    height, params.mHorizontalGap, params.mVerticalGap);
         }
     }
 }
diff --git a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
index 2bff107eb..a72f79137 100644
--- a/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/MoreKeysKeyboard.java
@@ -343,8 +343,7 @@ public final class MoreKeysKeyboard extends Keyboard {
                 final int row = n / params.mNumColumns;
                 final int x = params.getX(n, row);
                 final int y = params.getY(row);
-                final Key key = new Key(params, moreKeySpec, x, y,
-                        params.mDefaultKeyWidth, params.mDefaultRowHeight, moreKeyFlags);
+                final Key key = moreKeySpec.buildKey(x, y, moreKeyFlags, params);
                 params.markAsEdgeKey(key, row);
                 params.onAddKey(key);
 
diff --git a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
index 47e9142e2..340d184b6 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/KeyboardBuilder.java
@@ -21,6 +21,7 @@ import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
 import android.os.Build;
+import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.TypedValue;
@@ -37,6 +38,7 @@ import com.android.inputmethod.latin.utils.RunInLocale;
 import com.android.inputmethod.latin.utils.StringUtils;
 import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
 import com.android.inputmethod.latin.utils.XmlParseUtils;
+import com.android.inputmethod.latin.utils.XmlParseUtils.ParseException;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -455,11 +457,15 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
                 if (Build.VERSION.SDK_INT < supportedMinSdkVersion) {
                     continue;
                 }
+                final int labelFlags = row.getDefaultKeyLabelFlags();
+                final int backgroundType = row.getDefaultBackgroundType();
                 final int x = (int)row.getKeyX(null);
                 final int y = row.getKeyY();
-                final Key key = new Key(mParams, label, null /* hintLabel */, 0 /* iconId */,
-                        code, outputText, x, y, (int)keyWidth, row.getRowHeight(),
-                        row.getDefaultKeyLabelFlags(), row.getDefaultBackgroundType());
+                final int width = (int)keyWidth;
+                final int height = row.getRowHeight();
+                final Key key = new Key(label, KeyboardIconsSet.ICON_UNDEFINED, code, outputText,
+                        null /* hintLabel */, labelFlags, backgroundType, x, y, width, height,
+                        mParams.mHorizontalGap, mParams.mVerticalGap);
                 endKey(key);
                 row.advanceXPos(keyWidth);
             }
@@ -476,7 +482,15 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
             if (DEBUG) startEndTag("<%s /> skipped", TAG_KEY);
             return;
         }
-        final Key key = new Key(mResources, mParams, row, parser);
+        final TypedArray keyAttr = mResources.obtainAttributes(
+                Xml.asAttributeSet(parser), R.styleable.Keyboard_Key);
+        final KeyStyle keyStyle = mParams.mKeyStyles.getKeyStyle(keyAttr, parser);
+        final String keySpec = keyStyle.getString(keyAttr, R.styleable.Keyboard_Key_keySpec);
+        if (TextUtils.isEmpty(keySpec)) {
+            throw new ParseException("Empty keySpec", parser);
+        }
+        final Key key = new Key(keySpec, keyAttr, keyStyle, mParams, row);
+        keyAttr.recycle();
         if (DEBUG) {
             startEndTag("<%s%s %s moreKeys=%s />", TAG_KEY, (key.isEnabled() ? "" : " disabled"),
                     key, Arrays.toString(key.getMoreKeys()));
@@ -492,7 +506,11 @@ public class KeyboardBuilder<KP extends KeyboardParams> {
             if (DEBUG) startEndTag("<%s /> skipped", TAG_SPACER);
             return;
         }
-        final Key.Spacer spacer = new Key.Spacer(mResources, mParams, row, parser);
+        final TypedArray keyAttr = mResources.obtainAttributes(
+                Xml.asAttributeSet(parser), R.styleable.Keyboard_Key);
+        final KeyStyle keyStyle = mParams.mKeyStyles.getKeyStyle(keyAttr, parser);
+        final Key spacer = new Key.Spacer(keyAttr, keyStyle, mParams, row);
+        keyAttr.recycle();
         if (DEBUG) startEndTag("<%s />", TAG_SPACER);
         XmlParseUtils.checkEndTag(TAG_SPACER, parser);
         endKey(spacer);
diff --git a/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpec.java b/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpec.java
index bd440b875..319bf8921 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpec.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/MoreKeySpec.java
@@ -18,6 +18,7 @@ package com.android.inputmethod.keyboard.internal;
 
 import android.text.TextUtils;
 
+import com.android.inputmethod.keyboard.Key;
 import com.android.inputmethod.latin.Constants;
 import com.android.inputmethod.latin.LatinImeLogger;
 import com.android.inputmethod.latin.utils.CollectionUtils;
@@ -67,6 +68,13 @@ public final class MoreKeySpec {
         mIconId = KeySpecParser.getIconId(moreKeySpec);
     }
 
+    public Key buildKey(final int x, final int y, final int labelFlags,
+            final KeyboardParams params) {
+        return new Key(mLabel, mIconId, mCode, mOutputText, null /* hintLabel */, labelFlags,
+                Key.BACKGROUND_TYPE_NORMAL, x, y, params.mDefaultKeyWidth, params.mDefaultRowHeight,
+                params.mHorizontalGap, params.mVerticalGap);
+    }
+
     @Override
     public int hashCode() {
         int hashCode = 1;
diff --git a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
index b96175f02..2f4c1839b 100644
--- a/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
+++ b/java/src/com/android/inputmethod/latin/suggestions/MoreSuggestions.java
@@ -209,10 +209,10 @@ public final class MoreSuggestions extends Keyboard {
                 final String word = mSuggestedWords.getWord(index);
                 final String info = mSuggestedWords.getDebugString(index);
                 final int indexInMoreSuggestions = index + SUGGESTION_CODE_BASE;
-                final Key key = new Key(
-                        params, word, info, KeyboardIconsSet.ICON_UNDEFINED, indexInMoreSuggestions,
-                        null /* outputText */, x, y, width, params.mDefaultRowHeight,
-                        0 /* labelFlags */, Key.BACKGROUND_TYPE_NORMAL);
+                final Key key = new Key(word, KeyboardIconsSet.ICON_UNDEFINED,
+                        indexInMoreSuggestions, null /* outputText */, info, 0 /* labelFlags */,
+                        Key.BACKGROUND_TYPE_NORMAL, x, y, width, params.mDefaultRowHeight,
+                        params.mHorizontalGap, params.mVerticalGap);
                 params.markAsEdgeKey(key, index);
                 params.onAddKey(key);
                 final int columnNumber = params.getColumnNumber(index);