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.Constants; 22 import com.android.inputmethod.latin.utils.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 { 32 static ExpectedKeyOutput newInstance(final int code) { 33 return new Code(code); 34 } 35 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 44 abstract ExpectedKeyOutput toUpperCase(final Locale locale); 45 abstract ExpectedKeyOutput preserveCase(); 46 abstract boolean equalsTo(final String text); 47 abstract boolean equalsTo(final Key key); 48 abstract boolean equalsTo(final MoreKeySpec moreKeySpec); 49 abstract boolean equalsTo(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 58 Code(final int code) { mCode = code; } 59 60 @Override 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(codeString.toUpperCase(locale)); 67 } 68 // A special negative value has no upper case. 69 return this; 70 } 71 72 @Override 73 ExpectedKeyOutput preserveCase() { 74 return new CasePreservedCode(mCode); 75 } 76 77 @Override 78 boolean equalsTo(final String text) { 79 return StringUtils.codePointCount(text) == 1 && text.codePointAt(0) == mCode; 80 } 81 82 @Override 83 boolean equalsTo(final Key key) { 84 return mCode == key.getCode(); 85 } 86 87 @Override 88 boolean equalsTo(final MoreKeySpec moreKeySpec) { 89 return mCode == moreKeySpec.mCode; 90 } 91 92 @Override 93 boolean equalsTo(final ExpectedKeyOutput output) { 94 return (output instanceof Code) && mCode == ((Code)output).mCode; 95 } 96 97 @Override 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 { 104 CasePreservedCode(final int code) { super(code); } 105 106 @Override 107 ExpectedKeyOutput toUpperCase(final Locale locale) { return this; } 108 109 @Override 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 120 Text(final String text) { mText = text; } 121 122 @Override 123 ExpectedKeyOutput toUpperCase(final Locale locale) { 124 return newInstance(mText.toUpperCase(locale)); 125 } 126 127 @Override 128 ExpectedKeyOutput preserveCase() { 129 return new CasePreservedText(mText); 130 } 131 132 @Override 133 boolean equalsTo(final String text) { 134 return text.equals(text); 135 } 136 137 @Override 138 boolean equalsTo(final Key key) { 139 return key.getCode() == Constants.CODE_OUTPUT_TEXT 140 && mText.equals(key.getOutputText()); 141 } 142 143 @Override 144 boolean equalsTo(final MoreKeySpec moreKeySpec) { 145 return moreKeySpec.mCode == Constants.CODE_OUTPUT_TEXT 146 && mText.equals(moreKeySpec.mOutputText); 147 } 148 149 @Override 150 boolean equalsTo(final ExpectedKeyOutput output) { 151 return (output instanceof Text) && mText == ((Text)output).mText; 152 } 153 154 @Override 155 public String toString() { 156 return mText; 157 } 158 159 private static class CasePreservedText extends Text { 160 CasePreservedText(final String text) { super(text); } 161 162 @Override 163 ExpectedKeyOutput toUpperCase(final Locale locale) { return this; } 164 165 @Override 166 ExpectedKeyOutput preserveCase() { return this; } 167 } 168 } 169 } 170