ActualKeyboardBuilder.java revision cd15cfdaaba7f361f4744bd3ff51ce6cdae1e608
1ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka/* 2ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka * Copyright (C) 2014 The Android Open Source Project 3ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka * 4ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License"); 5ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka * you may not use this file except in compliance with the License. 6ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka * You may obtain a copy of the License at 7ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka * 8ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka * http://www.apache.org/licenses/LICENSE-2.0 9ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka * 10ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software 11ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS, 12ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka * See the License for the specific language governing permissions and 14ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka * limitations under the License. 15ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka */ 16ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka 17ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaokapackage com.android.inputmethod.keyboard.layout.expected; 18ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka 19ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaokaimport com.android.inputmethod.keyboard.Key; 20ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.KeyboardIconsSet; 21ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.MoreKeySpec; 22ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaokaimport com.android.inputmethod.latin.Constants; 23ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaokaimport com.android.inputmethod.latin.utils.CollectionUtils; 24ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaokaimport com.android.inputmethod.latin.utils.StringUtils; 25ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka 26ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaokaimport java.util.ArrayList; 27ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaokaimport java.util.Collections; 28ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaokaimport java.util.Comparator; 29ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka 30ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka/** 31ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka * This class builds an actual keyboard for unit test. 32ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka */ 33ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaokapublic final class ActualKeyboardBuilder extends AbstractKeyboardBuilder<Key> { 34ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka // Comparator to sort {@link Key}s from top-left to bottom-right order. 35ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka private static final Comparator<Key> ROW_COLUMN_COMPARATOR = new Comparator<Key>() { 36ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka @Override 37ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka public int compare(final Key lhs, final Key rhs) { 38ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka if (lhs.getY() < rhs.getY()) return -1; 39ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka if (lhs.getY() > rhs.getY()) return 1; 40ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka if (lhs.getX() < rhs.getX()) return -1; 41ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka if (lhs.getX() > rhs.getX()) return 1; 42ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka return 0; 43ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka } 44ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka }; 45ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka 468c6b34e51dfd139d55ad1ea7d6e39a7223117fc3Tadashi G. Takaoka private static ArrayList<Key> filterOutSpacerAndSortKeys(final Key[] keys) { 478c6b34e51dfd139d55ad1ea7d6e39a7223117fc3Tadashi G. Takaoka final ArrayList<Key> filteredKeys = CollectionUtils.newArrayList(); 488c6b34e51dfd139d55ad1ea7d6e39a7223117fc3Tadashi G. Takaoka for (final Key key : keys) { 498c6b34e51dfd139d55ad1ea7d6e39a7223117fc3Tadashi G. Takaoka if (key.isSpacer()) { 508c6b34e51dfd139d55ad1ea7d6e39a7223117fc3Tadashi G. Takaoka continue; 518c6b34e51dfd139d55ad1ea7d6e39a7223117fc3Tadashi G. Takaoka } 528c6b34e51dfd139d55ad1ea7d6e39a7223117fc3Tadashi G. Takaoka filteredKeys.add(key); 538c6b34e51dfd139d55ad1ea7d6e39a7223117fc3Tadashi G. Takaoka } 548c6b34e51dfd139d55ad1ea7d6e39a7223117fc3Tadashi G. Takaoka Collections.sort(filteredKeys, ROW_COLUMN_COMPARATOR); 558c6b34e51dfd139d55ad1ea7d6e39a7223117fc3Tadashi G. Takaoka return filteredKeys; 568c6b34e51dfd139d55ad1ea7d6e39a7223117fc3Tadashi G. Takaoka } 578c6b34e51dfd139d55ad1ea7d6e39a7223117fc3Tadashi G. Takaoka 58ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka /** 59ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka * Create the keyboard that consists of the array of rows of the actual keyboard's keys. 60ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka * @param keys the array of keys of the actual keyboard. 61ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka * @return the actual keyboard grouped with rows. 62ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka */ 63ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka public static Key[][] buildKeyboard(final Key[] keys) { 648c6b34e51dfd139d55ad1ea7d6e39a7223117fc3Tadashi G. Takaoka // Filter out spacer and sort keys from top-left to bottom-right order to prepare to 658c6b34e51dfd139d55ad1ea7d6e39a7223117fc3Tadashi G. Takaoka // create rows. 668c6b34e51dfd139d55ad1ea7d6e39a7223117fc3Tadashi G. Takaoka final ArrayList<Key> sortedKeys = filterOutSpacerAndSortKeys(keys); 67ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka 68ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka // Grouping keys into rows. 69ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka final ArrayList<ArrayList<Key>> rows = CollectionUtils.newArrayList(); 70ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka ArrayList<Key> elements = CollectionUtils.newArrayList(); 71ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka int lastY = sortedKeys.get(0).getY(); 72ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka for (final Key key : sortedKeys) { 73ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka if (lastY != key.getY()) { 74ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka // A new row is starting. 75ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka lastY = key.getY(); 76ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka rows.add(elements); 77ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka elements = CollectionUtils.newArrayList(); 78ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka } 79ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka elements.add(key); 80ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka } 81ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka rows.add(elements); // Add the last row. 82ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka 83ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka // Calculate each dimension of rows and create a builder. 84ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka final int[] dimensions = new int[rows.size()]; 85ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka for (int rowIndex = 0; rowIndex < dimensions.length; rowIndex++) { 86ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka dimensions[rowIndex] = rows.get(rowIndex).size(); 87ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka } 88cd15cfdaaba7f361f4744bd3ff51ce6cdae1e608Tadashi G. Takaoka final ActualKeyboardBuilder builder = new ActualKeyboardBuilder(); 89ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka 90ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka for (int rowIndex = 0; rowIndex < rows.size(); rowIndex++) { 91ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka final int row = rowIndex + 1; 92ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka final ArrayList<Key> rowKeys = rows.get(rowIndex); 93ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka builder.setRowAt(row, rowKeys.toArray(new Key[rowKeys.size()])); 94ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka } 95ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka return builder.build(); 96ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka } 97ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka 98ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka @Override 99ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka Key defaultElement() { return null; } 100ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka 101ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka @Override 102ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka Key[] newArray(final int size) { return new Key[size]; } 103ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka 104ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka @Override 105ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka Key[][] newArrayOfArray(final int size) { return new Key[size][]; } 106ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka 107ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka // Helper class to create concise representation from the key specification. 108ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka static class MoreKeySpecStringizer extends StringUtils.Stringizer<MoreKeySpec> { 109ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka static final MoreKeySpecStringizer STRINGIZER = new MoreKeySpecStringizer(); 110ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka 111ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka @Override 112ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka public String stringize(final MoreKeySpec spec) { 113ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka return toString(spec.mLabel, spec.mIconId, spec.mOutputText, spec.mCode); 114ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka } 115ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka 116ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka static String toString(final String label, final int iconId, final String outputText, 117ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka final int code) { 118ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka final String visual = (iconId != KeyboardIconsSet.ICON_UNDEFINED) 119ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka ? KeyboardIconsSet.getIconName(iconId) : label; 120ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka final String output; 121ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka if (code == Constants.CODE_OUTPUT_TEXT) { 122ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka output = outputText; 123ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka } else if (code < Constants.CODE_SPACE) { 124ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka output = Constants.printableCode(code); 125ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka } else { 126ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka output = StringUtils.newSingleCodePointString(code); 127ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka } 128ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka if (visual.equals(output)) { 129ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka return visual; 130ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka } 131ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka return visual + "|" + output; 132ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka } 133ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka } 134ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka 135ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka // Helper class to create concise representation from the key. 136ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka static class KeyStringizer extends StringUtils.Stringizer<Key> { 137ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka static final KeyStringizer STRINGIZER = new KeyStringizer(); 138ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka 139ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka @Override 140ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka public String stringize(final Key key) { 141ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka if (key == null) { 142ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka return "NULL"; 143ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka } 144ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka if (key.isSpacer()) { 145ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka return "SPACER"; 146ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka } 147ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka final StringBuilder sb = new StringBuilder(); 148ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka sb.append(MoreKeySpecStringizer.toString( 149ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka key.getLabel(), key.getIconId(), key.getOutputText(), key.getCode())); 150ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka final MoreKeySpec[] moreKeys = key.getMoreKeys(); 151ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka if (moreKeys == null) { 152ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka return sb.toString(); 153ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka } 154ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka sb.append("^"); 155ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka sb.append(MoreKeySpecStringizer.STRINGIZER.join(moreKeys)); 156ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka return sb.toString(); 157ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka } 158ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka } 159ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka 160ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka /** 161ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka * Convert the key to human readable string. 162ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka * @param key the key to be converted to string. 163ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka * @return the human readable representation of <code>key</code>. 164ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka */ 165ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka public static String toString(final Key key) { 166ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka return KeyStringizer.STRINGIZER.stringize(key); 167ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka } 168ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka 169ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka /** 170ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka * Convert the keyboard row to human readable string. 171ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka * @param keys the keyboard row to be converted to string. 172ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka * @return the human readable representation of <code>keys</code>. 173ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka */ 174ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka public static String toString(final Key[] keys) { 175ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka return KeyStringizer.STRINGIZER.join(keys); 176ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka } 177ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka 178ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka // Helper class to create concise representation from the array of the key. 179ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka static class KeyArrayStringizer extends StringUtils.Stringizer<Key[]> { 180ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka static final KeyArrayStringizer STRINGIZER = new KeyArrayStringizer(); 181ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka 182ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka @Override 183ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka public String stringize(final Key[] keyArray) { 184ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka return KeyStringizer.STRINGIZER.join(keyArray); 185ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka } 186ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka } 187ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka 188ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka /** 189ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka * Convert the keyboard to human readable string. 190ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka * @param rows the keyboard to be converted to string. 191ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka * @return the human readable representation of <code>rows</code>. 192ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka */ 193ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka public static String toString(final Key[][] rows) { 194ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka return KeyArrayStringizer.STRINGIZER.join(rows, "\n" /* delimiter */); 195ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka } 196ff8405cdfbd575657a6f615a1ac4d86eb1b07f74Tadashi G. Takaoka} 197