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.MoreKeySpec; 21 import com.android.inputmethod.latin.common.Constants; 22 import com.android.inputmethod.latin.common.StringUtils; 23 24 import java.util.Locale; 25 26 /** 27 * This class represents an expected output of a key. 28 * 29 * There are two types of expected output, an integer code point and a string output text. 30 */ 31 abstract class ExpectedKeyOutput { newInstance(final int code)32 static ExpectedKeyOutput newInstance(final int code) { 33 return new Code(code); 34 } 35 newInstance(final String outputText)36 static ExpectedKeyOutput newInstance(final String outputText) { 37 // If the <code>outputText</code> is one code point string, use {@link CodePoint} object. 38 if (StringUtils.codePointCount(outputText) == 1) { 39 return new Code(outputText.codePointAt(0)); 40 } 41 return new Text(outputText); 42 } 43 toUpperCase(final Locale locale)44 abstract ExpectedKeyOutput toUpperCase(final Locale locale); preserveCase()45 abstract ExpectedKeyOutput preserveCase(); hasSameKeyOutput(final String text)46 abstract boolean hasSameKeyOutput(final String text); hasSameKeyOutput(final Key key)47 abstract boolean hasSameKeyOutput(final Key key); hasSameKeyOutput(final MoreKeySpec moreKeySpec)48 abstract boolean hasSameKeyOutput(final MoreKeySpec moreKeySpec); hasSameKeyOutput(final ExpectedKeyOutput output)49 abstract boolean hasSameKeyOutput(final ExpectedKeyOutput output); 50 51 /** 52 * This class represents an integer code point. 53 */ 54 private static class Code extends ExpectedKeyOutput { 55 // UNICODE code point or a special negative value defined in {@link Constants}. 56 private final int mCode; 57 Code(final int code)58 Code(final int code) { mCode = code; } 59 60 @Override toUpperCase(final Locale locale)61 ExpectedKeyOutput toUpperCase(final Locale locale) { 62 if (Constants.isLetterCode(mCode)) { 63 final String codeString = StringUtils.newSingleCodePointString(mCode); 64 // A letter may have an upper case counterpart that consists of multiple code 65 // points, for instance the upper case of "ß" is "SS". 66 return newInstance(StringUtils.toTitleCaseOfKeyLabel(codeString, locale)); 67 } 68 // A special negative value has no upper case. 69 return this; 70 } 71 72 @Override preserveCase()73 ExpectedKeyOutput preserveCase() { 74 return new CasePreservedCode(mCode); 75 } 76 77 @Override hasSameKeyOutput(final String text)78 boolean hasSameKeyOutput(final String text) { 79 return StringUtils.codePointCount(text) == 1 && text.codePointAt(0) == mCode; 80 } 81 82 @Override hasSameKeyOutput(final Key key)83 boolean hasSameKeyOutput(final Key key) { 84 return mCode == key.getCode(); 85 } 86 87 @Override hasSameKeyOutput(final MoreKeySpec moreKeySpec)88 boolean hasSameKeyOutput(final MoreKeySpec moreKeySpec) { 89 return mCode == moreKeySpec.mCode; 90 } 91 92 @Override hasSameKeyOutput(final ExpectedKeyOutput output)93 boolean hasSameKeyOutput(final ExpectedKeyOutput output) { 94 return (output instanceof Code) && mCode == ((Code)output).mCode; 95 } 96 97 @Override toString()98 public String toString() { 99 return Constants.isLetterCode(mCode) ? StringUtils.newSingleCodePointString(mCode) 100 : Constants.printableCode(mCode); 101 } 102 103 private static class CasePreservedCode extends Code { CasePreservedCode(final int code)104 CasePreservedCode(final int code) { super(code); } 105 106 @Override toUpperCase(final Locale locale)107 ExpectedKeyOutput toUpperCase(final Locale locale) { return this; } 108 109 @Override preserveCase()110 ExpectedKeyOutput preserveCase() { return this; } 111 } 112 } 113 114 /** 115 * This class represents a string output text. 116 */ 117 private static class Text extends ExpectedKeyOutput { 118 private final String mText; 119 Text(final String text)120 Text(final String text) { mText = text; } 121 122 @Override toUpperCase(final Locale locale)123 ExpectedKeyOutput toUpperCase(final Locale locale) { 124 return newInstance(mText.toUpperCase(locale)); 125 } 126 127 @Override preserveCase()128 ExpectedKeyOutput preserveCase() { 129 return new CasePreservedText(mText); 130 } 131 132 @Override hasSameKeyOutput(final String text)133 boolean hasSameKeyOutput(final String text) { 134 return text.equals(text); 135 } 136 137 @Override hasSameKeyOutput(final Key key)138 boolean hasSameKeyOutput(final Key key) { 139 return key.getCode() == Constants.CODE_OUTPUT_TEXT 140 && mText.equals(key.getOutputText()); 141 } 142 143 @Override hasSameKeyOutput(final MoreKeySpec moreKeySpec)144 boolean hasSameKeyOutput(final MoreKeySpec moreKeySpec) { 145 return moreKeySpec.mCode == Constants.CODE_OUTPUT_TEXT 146 && mText.equals(moreKeySpec.mOutputText); 147 } 148 149 @Override hasSameKeyOutput(final ExpectedKeyOutput output)150 boolean hasSameKeyOutput(final ExpectedKeyOutput output) { 151 return (output instanceof Text) && mText == ((Text)output).mText; 152 } 153 154 @Override toString()155 public String toString() { 156 return mText; 157 } 158 159 private static class CasePreservedText extends Text { CasePreservedText(final String text)160 CasePreservedText(final String text) { super(text); } 161 162 @Override toUpperCase(final Locale locale)163 ExpectedKeyOutput toUpperCase(final Locale locale) { return this; } 164 165 @Override preserveCase()166 ExpectedKeyOutput preserveCase() { return this; } 167 } 168 } 169 } 170