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