Use unmodifiable list to return keys from Keyboard

Change-Id: I85a0b18d2d78632e9a9f074eda1de9225001f876
diff --git a/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java b/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
index c628c5b..ae826fe 100644
--- a/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
+++ b/java/src/com/android/inputmethod/accessibility/AccessibilityEntityProvider.java
@@ -159,8 +159,7 @@
 
             // Add the virtual children of the root View.
             final Keyboard keyboard = mKeyboardView.getKeyboard();
-            final Key[] keys = keyboard.getKeys();
-            for (Key key : keys) {
+            for (final Key key : keyboard.getKeys()) {
                 final int childVirtualViewId = generateVirtualViewIdForKey(key);
                 rootInfo.addChild(mKeyboardView, childVirtualViewId);
             }
@@ -308,8 +307,7 @@
         }
         mVirtualViewIdToKey.clear();
 
-        final Key[] keys = keyboard.getKeys();
-        for (Key key : keys) {
+        for (final Key key : keyboard.getKeys()) {
             final int virtualViewId = generateVirtualViewIdForKey(key);
             mVirtualViewIdToKey.put(virtualViewId, key);
         }
diff --git a/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java b/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java
index ad99697..3c50401 100644
--- a/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java
+++ b/java/src/com/android/inputmethod/keyboard/EmojiPalettesView.java
@@ -58,9 +58,10 @@
 import com.android.inputmethod.latin.utils.ResourceUtils;
 
 import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
+import java.util.List;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.TimeUnit;
 
@@ -297,7 +298,7 @@
 
         private int getCategoryPageCount(final int categoryId) {
             final Keyboard keyboard = mLayoutSet.getKeyboard(sCategoryElementId[categoryId]);
-            return (keyboard.getKeys().length - 1) / mMaxPageKeyCount + 1;
+            return (keyboard.getKeys().size() - 1) / mMaxPageKeyCount + 1;
         }
 
         // Returns a pair of the category id and the category page id from the view pager's page
@@ -394,13 +395,13 @@
             }
         };
 
-        private static Key[][] sortKeysIntoPages(final Key[] inKeys, final int maxPageCount) {
-            final Key[] keys = Arrays.copyOf(inKeys, inKeys.length);
-            Arrays.sort(keys, 0, keys.length, EMOJI_KEY_COMPARATOR);
-            final int pageCount = (keys.length - 1) / maxPageCount + 1;
+        private static Key[][] sortKeysIntoPages(final List<Key> inKeys, final int maxPageCount) {
+            final ArrayList<Key> keys = CollectionUtils.newArrayList(inKeys);
+            Collections.sort(keys, EMOJI_KEY_COMPARATOR);
+            final int pageCount = (keys.size() - 1) / maxPageCount + 1;
             final Key[][] retval = new Key[pageCount][maxPageCount];
-            for (int i = 0; i < keys.length; ++i) {
-                retval[i / maxPageCount][i % maxPageCount] = keys[i];
+            for (int i = 0; i < keys.size(); ++i) {
+                retval[i / maxPageCount][i % maxPageCount] = keys.get(i);
             }
             return retval;
         }
diff --git a/java/src/com/android/inputmethod/keyboard/Keyboard.java b/java/src/com/android/inputmethod/keyboard/Keyboard.java
index e6a1441..5162770 100644
--- a/java/src/com/android/inputmethod/keyboard/Keyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/Keyboard.java
@@ -77,8 +77,8 @@
     /** Maximum column for more keys keyboard */
     public final int mMaxMoreKeysKeyboardColumn;
 
-    /** Array of keys and icons in this keyboard */
-    private final Key[] mKeys;
+    /** List of keys in this keyboard */
+    private final List<Key> mKeys;
     public final List<Key> mShiftKeys;
     public final List<Key> mAltCodeKeysWhileTyping;
     public final KeyboardIconsSet mIconsSet;
@@ -103,7 +103,7 @@
         mTopPadding = params.mTopPadding;
         mVerticalGap = params.mVerticalGap;
 
-        mKeys = params.mKeys.toArray(new Key[params.mKeys.size()]);
+        mKeys = Collections.unmodifiableList(CollectionUtils.newArrayList(params.mKeys));
         mShiftKeys = Collections.unmodifiableList(params.mShiftKeys);
         mAltCodeKeysWhileTyping = Collections.unmodifiableList(params.mAltCodeKeysWhileTyping);
         mIconsSet = params.mIconsSet;
@@ -154,7 +154,7 @@
         return mProximityInfo;
     }
 
-    public Key[] getKeys() {
+    public List<Key> getKeys() {
         return mKeys;
     }
 
diff --git a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
index 3a4e335..fdb20f8 100644
--- a/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
+++ b/java/src/com/android/inputmethod/keyboard/ProximityInfo.java
@@ -51,13 +51,13 @@
     private final int mKeyboardHeight;
     private final int mMostCommonKeyWidth;
     private final int mMostCommonKeyHeight;
-    private final Key[] mKeys;
+    private final List<Key> mKeys;
     private final List<Key>[] mGridNeighbors;
     private final String mLocaleStr;
 
     ProximityInfo(final String localeStr, final int gridWidth, final int gridHeight,
             final int minWidth, final int height, final int mostCommonKeyWidth,
-            final int mostCommonKeyHeight, final Key[] keys,
+            final int mostCommonKeyHeight, final List<Key> keys,
             final TouchPositionCorrection touchPositionCorrection) {
         if (TextUtils.isEmpty(localeStr)) {
             mLocaleStr = "";
@@ -103,7 +103,7 @@
         return key.getCode() >= Constants.CODE_SPACE;
     }
 
-    private static int getProximityInfoKeysCount(final Key[] keys) {
+    private static int getProximityInfoKeysCount(final List<Key> keys) {
         int count = 0;
         for (final Key key : keys) {
             if (needsProximityInfo(key)) {
@@ -146,7 +146,7 @@
             }
         }
 
-        final Key[] keys = mKeys;
+        final List<Key> keys = mKeys;
         final int keyCount = getProximityInfoKeysCount(keys);
         final int[] keyXCoordinates = new int[keyCount];
         final int[] keyYCoordinates = new int[keyCount];
@@ -157,8 +157,8 @@
         final float[] sweetSpotCenterYs;
         final float[] sweetSpotRadii;
 
-        for (int infoIndex = 0, keyIndex = 0; keyIndex < keys.length; keyIndex++) {
-            final Key key = keys[keyIndex];
+        for (int infoIndex = 0, keyIndex = 0; keyIndex < keys.size(); keyIndex++) {
+            final Key key = keys.get(keyIndex);
             // Excluding from key coordinate arrays
             if (!needsProximityInfo(key)) {
                 continue;
@@ -181,8 +181,8 @@
             final int rows = touchPositionCorrection.getRows();
             final float defaultRadius = DEFAULT_TOUCH_POSITION_CORRECTION_RADIUS
                     * (float)Math.hypot(mMostCommonKeyWidth, mMostCommonKeyHeight);
-            for (int infoIndex = 0, keyIndex = 0; keyIndex < keys.length; keyIndex++) {
-                final Key key = keys[keyIndex];
+            for (int infoIndex = 0, keyIndex = 0; keyIndex < keys.size(); keyIndex++) {
+                final Key key = keys.get(keyIndex);
                 // Excluding from touch position correction arrays
                 if (!needsProximityInfo(key)) {
                     continue;
@@ -244,7 +244,7 @@
 
     private void computeNearestNeighbors() {
         final int defaultWidth = mMostCommonKeyWidth;
-        final int keyCount = mKeys.length;
+        final int keyCount = mKeys.size();
         final int gridSize = mGridNeighbors.length;
         final int threshold = (int) (defaultWidth * SEARCH_DISTANCE);
         final int thresholdSquared = threshold * threshold;
diff --git a/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java b/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java
index ac7df30..dd5ec1d 100644
--- a/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java
+++ b/java/src/com/android/inputmethod/keyboard/internal/DynamicGridKeyboard.java
@@ -31,6 +31,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -51,7 +52,7 @@
     private final ArrayDeque<GridKey> mGridKeys = CollectionUtils.newArrayDeque();
     private final ArrayDeque<Key> mPendingKeys = CollectionUtils.newArrayDeque();
 
-    private Key[] mCachedGridKeys;
+    private List<Key> mCachedGridKeys;
 
     public DynamicGridKeyboard(final SharedPreferences prefs, final Keyboard templateKeyboard,
             final int maxKeyCount, final int categoryId) {
@@ -206,12 +207,14 @@
     }
 
     @Override
-    public Key[] getKeys() {
+    public List<Key> getKeys() {
         synchronized (mLock) {
             if (mCachedGridKeys != null) {
                 return mCachedGridKeys;
             }
-            mCachedGridKeys = mGridKeys.toArray(new Key[mGridKeys.size()]);
+            final ArrayList<Key> cachedKeys = CollectionUtils.newArrayList(mGridKeys.size());
+            cachedKeys.addAll(mGridKeys);
+            mCachedGridKeys = Collections.unmodifiableList(cachedKeys);
             return mCachedGridKeys;
         }
     }
@@ -219,7 +222,7 @@
     @Override
     public List<Key> getNearestKeys(final int x, final int y) {
         // TODO: Calculate the nearest key index in mGridKeys from x and y.
-        return Arrays.asList(getKeys());
+        return getKeys();
     }
 
     static final class GridKey extends Key {
diff --git a/tests/src/com/android/inputmethod/keyboard/layout/expected/ActualKeyboardBuilder.java b/tests/src/com/android/inputmethod/keyboard/layout/expected/ActualKeyboardBuilder.java
index 050bc4c..b0cd4df 100644
--- a/tests/src/com/android/inputmethod/keyboard/layout/expected/ActualKeyboardBuilder.java
+++ b/tests/src/com/android/inputmethod/keyboard/layout/expected/ActualKeyboardBuilder.java
@@ -26,6 +26,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.List;
 
 /**
  * This class builds an actual keyboard for unit test.
@@ -43,7 +44,7 @@
         }
     };
 
-    private static ArrayList<Key> filterOutSpacerAndSortKeys(final Key[] keys) {
+    private static ArrayList<Key> filterOutSpacerAndSortKeys(final List<Key> keys) {
         final ArrayList<Key> filteredKeys = CollectionUtils.newArrayList();
         for (final Key key : keys) {
             if (key.isSpacer()) {
@@ -57,10 +58,10 @@
 
     /**
      * Create the keyboard that consists of the array of rows of the actual keyboard's keys.
-     * @param keys the array of keys of the actual keyboard.
+     * @param keys the list of keys of the actual keyboard.
      * @return the actual keyboard grouped with rows.
      */
-    public static Key[][] buildKeyboard(final Key[] keys) {
+    public static Key[][] buildKeyboard(final List<Key> keys) {
         // Filter out spacer and sort keys from top-left to bottom-right order to prepare to
         // create rows.
         final ArrayList<Key> sortedKeys = filterOutSpacerAndSortKeys(keys);