1c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka/*
2c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka * Copyright (C) 2014 The Android Open Source Project
3c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka *
4c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License");
5c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka * you may not use this file except in compliance with the License.
6c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka * You may obtain a copy of the License at
7c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka *
8c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka *      http://www.apache.org/licenses/LICENSE-2.0
9c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka *
10c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software
11c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS,
12c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka * See the License for the specific language governing permissions and
14c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka * limitations under the License.
15c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka */
16c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka
17c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaokapackage com.android.inputmethod.keyboard.layout.expected;
18c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka
19c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaokaimport com.android.inputmethod.keyboard.Key;
20c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.MoreKeySpec;
219342484e8d573a40f470b6a593df31c602fa4076Ken Wakasaimport com.android.inputmethod.latin.common.Constants;
224beeb9253a06482299e0c67467531d30436a02fcJean Chalardimport com.android.inputmethod.latin.common.StringUtils;
23c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka
24c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaokaimport java.util.Locale;
25c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka
26c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka/**
27c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka * This class represents an expected output of a key.
28c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka *
29c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka * There are two types of expected output, an integer code point and a string output text.
30c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka */
31c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaokaabstract class ExpectedKeyOutput {
32c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka    static ExpectedKeyOutput newInstance(final int code) {
33c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        return new Code(code);
34c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka    }
35c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka
36c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka    static ExpectedKeyOutput newInstance(final String outputText) {
37c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        // If the <code>outputText</code> is one code point string, use {@link CodePoint} object.
38c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        if (StringUtils.codePointCount(outputText) == 1) {
39c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka            return new Code(outputText.codePointAt(0));
40c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        }
41c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        return new Text(outputText);
42c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka    }
43c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka
44c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka    abstract ExpectedKeyOutput toUpperCase(final Locale locale);
45c9aa1beb6de6bbea71af8eba94354bff3001e0acTadashi G. Takaoka    abstract ExpectedKeyOutput preserveCase();
4651333ba4c36726a2f7acff859cd8ffb782e8f2b3Tadashi G. Takaoka    abstract boolean hasSameKeyOutput(final String text);
4751333ba4c36726a2f7acff859cd8ffb782e8f2b3Tadashi G. Takaoka    abstract boolean hasSameKeyOutput(final Key key);
4851333ba4c36726a2f7acff859cd8ffb782e8f2b3Tadashi G. Takaoka    abstract boolean hasSameKeyOutput(final MoreKeySpec moreKeySpec);
4951333ba4c36726a2f7acff859cd8ffb782e8f2b3Tadashi G. Takaoka    abstract boolean hasSameKeyOutput(final ExpectedKeyOutput output);
50c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka
51c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka    /**
52c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka     * This class represents an integer code point.
53c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka     */
54c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka    private static class Code extends ExpectedKeyOutput {
55c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        // UNICODE code point or a special negative value defined in {@link Constants}.
56c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        private final int mCode;
57c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka
58c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        Code(final int code) { mCode = code; }
59c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka
60c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        @Override
61c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        ExpectedKeyOutput toUpperCase(final Locale locale) {
62c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka            if (Constants.isLetterCode(mCode)) {
63c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka                final String codeString = StringUtils.newSingleCodePointString(mCode);
64c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka                // A letter may have an upper case counterpart that consists of multiple code
65c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka                // points, for instance the upper case of "ß" is "SS".
666c47403e27fd703ece844f4b1b24632721da1772Tadashi G. Takaoka                return newInstance(StringUtils.toTitleCaseOfKeyLabel(codeString, locale));
67c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka            }
68c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka            // A special negative value has no upper case.
69c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka            return this;
70c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        }
71c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka
72c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        @Override
73c9aa1beb6de6bbea71af8eba94354bff3001e0acTadashi G. Takaoka        ExpectedKeyOutput preserveCase() {
74c9aa1beb6de6bbea71af8eba94354bff3001e0acTadashi G. Takaoka            return new CasePreservedCode(mCode);
75c9aa1beb6de6bbea71af8eba94354bff3001e0acTadashi G. Takaoka        }
76c9aa1beb6de6bbea71af8eba94354bff3001e0acTadashi G. Takaoka
77c9aa1beb6de6bbea71af8eba94354bff3001e0acTadashi G. Takaoka        @Override
7851333ba4c36726a2f7acff859cd8ffb782e8f2b3Tadashi G. Takaoka        boolean hasSameKeyOutput(final String text) {
79c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka            return StringUtils.codePointCount(text) == 1 && text.codePointAt(0) == mCode;
80c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        }
81c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka
82c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        @Override
8351333ba4c36726a2f7acff859cd8ffb782e8f2b3Tadashi G. Takaoka        boolean hasSameKeyOutput(final Key key) {
84c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka            return mCode == key.getCode();
85c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        }
86c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka
87c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        @Override
8851333ba4c36726a2f7acff859cd8ffb782e8f2b3Tadashi G. Takaoka        boolean hasSameKeyOutput(final MoreKeySpec moreKeySpec) {
89c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka            return mCode == moreKeySpec.mCode;
90c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        }
91c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka
92c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        @Override
9351333ba4c36726a2f7acff859cd8ffb782e8f2b3Tadashi G. Takaoka        boolean hasSameKeyOutput(final ExpectedKeyOutput output) {
94c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka            return (output instanceof Code) && mCode == ((Code)output).mCode;
95c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        }
96c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka
97c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        @Override
98c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        public String toString() {
99c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka            return Constants.isLetterCode(mCode) ? StringUtils.newSingleCodePointString(mCode)
100c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka                    : Constants.printableCode(mCode);
101c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        }
102c9aa1beb6de6bbea71af8eba94354bff3001e0acTadashi G. Takaoka
103c9aa1beb6de6bbea71af8eba94354bff3001e0acTadashi G. Takaoka        private static class CasePreservedCode extends Code {
104c9aa1beb6de6bbea71af8eba94354bff3001e0acTadashi G. Takaoka            CasePreservedCode(final int code) { super(code); }
105c9aa1beb6de6bbea71af8eba94354bff3001e0acTadashi G. Takaoka
106c9aa1beb6de6bbea71af8eba94354bff3001e0acTadashi G. Takaoka            @Override
107c9aa1beb6de6bbea71af8eba94354bff3001e0acTadashi G. Takaoka            ExpectedKeyOutput toUpperCase(final Locale locale) { return this; }
108c9aa1beb6de6bbea71af8eba94354bff3001e0acTadashi G. Takaoka
109c9aa1beb6de6bbea71af8eba94354bff3001e0acTadashi G. Takaoka            @Override
110c9aa1beb6de6bbea71af8eba94354bff3001e0acTadashi G. Takaoka            ExpectedKeyOutput preserveCase() { return this; }
111c9aa1beb6de6bbea71af8eba94354bff3001e0acTadashi G. Takaoka        }
112c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka    }
113c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka
114c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka    /**
115c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka     * This class represents a string output text.
116c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka     */
117c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka    private static class Text extends ExpectedKeyOutput {
118c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        private final String mText;
119c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka
120c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        Text(final String text) { mText = text; }
121c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka
122c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        @Override
123c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        ExpectedKeyOutput toUpperCase(final Locale locale) {
124c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka            return newInstance(mText.toUpperCase(locale));
125c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        }
126c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka
127c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        @Override
128c9aa1beb6de6bbea71af8eba94354bff3001e0acTadashi G. Takaoka        ExpectedKeyOutput preserveCase() {
129c9aa1beb6de6bbea71af8eba94354bff3001e0acTadashi G. Takaoka            return new CasePreservedText(mText);
130c9aa1beb6de6bbea71af8eba94354bff3001e0acTadashi G. Takaoka        }
131c9aa1beb6de6bbea71af8eba94354bff3001e0acTadashi G. Takaoka
132c9aa1beb6de6bbea71af8eba94354bff3001e0acTadashi G. Takaoka        @Override
13351333ba4c36726a2f7acff859cd8ffb782e8f2b3Tadashi G. Takaoka        boolean hasSameKeyOutput(final String text) {
134c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka            return text.equals(text);
135c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        }
136c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka
137c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        @Override
13851333ba4c36726a2f7acff859cd8ffb782e8f2b3Tadashi G. Takaoka        boolean hasSameKeyOutput(final Key key) {
139c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka            return key.getCode() == Constants.CODE_OUTPUT_TEXT
140c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka                    && mText.equals(key.getOutputText());
141c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        }
142c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka
143c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        @Override
14451333ba4c36726a2f7acff859cd8ffb782e8f2b3Tadashi G. Takaoka        boolean hasSameKeyOutput(final MoreKeySpec moreKeySpec) {
145c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka            return moreKeySpec.mCode == Constants.CODE_OUTPUT_TEXT
146c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka                    && mText.equals(moreKeySpec.mOutputText);
147c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        }
148c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka
149c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        @Override
15051333ba4c36726a2f7acff859cd8ffb782e8f2b3Tadashi G. Takaoka        boolean hasSameKeyOutput(final ExpectedKeyOutput output) {
151c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka            return (output instanceof Text) && mText == ((Text)output).mText;
152c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        }
153c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka
154c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        @Override
155c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        public String toString() {
156c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka            return mText;
157c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka        }
158c9aa1beb6de6bbea71af8eba94354bff3001e0acTadashi G. Takaoka
159c9aa1beb6de6bbea71af8eba94354bff3001e0acTadashi G. Takaoka        private static class CasePreservedText extends Text {
160c9aa1beb6de6bbea71af8eba94354bff3001e0acTadashi G. Takaoka            CasePreservedText(final String text) { super(text); }
161c9aa1beb6de6bbea71af8eba94354bff3001e0acTadashi G. Takaoka
162c9aa1beb6de6bbea71af8eba94354bff3001e0acTadashi G. Takaoka            @Override
163c9aa1beb6de6bbea71af8eba94354bff3001e0acTadashi G. Takaoka            ExpectedKeyOutput toUpperCase(final Locale locale) { return this; }
164c9aa1beb6de6bbea71af8eba94354bff3001e0acTadashi G. Takaoka
165c9aa1beb6de6bbea71af8eba94354bff3001e0acTadashi G. Takaoka            @Override
166c9aa1beb6de6bbea71af8eba94354bff3001e0acTadashi G. Takaoka            ExpectedKeyOutput preserveCase() { return this; }
167c9aa1beb6de6bbea71af8eba94354bff3001e0acTadashi G. Takaoka        }
168c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka    }
169c39c912a331c9993438783c6eb03910aa314813dTadashi G. Takaoka}
170