• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.latin;
18 
19 import static com.android.inputmethod.latin.common.Constants.Subtype.KEYBOARD_MODE;
20 
21 import android.util.Log;
22 import android.view.inputmethod.InputMethodSubtype;
23 
24 import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils;
25 import com.android.inputmethod.latin.common.Constants;
26 import com.android.inputmethod.latin.common.LocaleUtils;
27 import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
28 
29 import java.util.Locale;
30 
31 import javax.annotation.Nonnull;
32 import javax.annotation.Nullable;
33 
34 /**
35  * Enrichment class for InputMethodSubtype to enable concurrent multi-lingual input.
36  *
37  * Right now, this returns the extra value of its primary subtype.
38  */
39 // non final for easy mocking.
40 public class RichInputMethodSubtype {
41     private static final String TAG = RichInputMethodSubtype.class.getSimpleName();
42 
43     @Nonnull
44     private final InputMethodSubtype mSubtype;
45     @Nonnull
46     private final Locale mLocale;
47 
RichInputMethodSubtype(@onnull final InputMethodSubtype subtype)48     public RichInputMethodSubtype(@Nonnull final InputMethodSubtype subtype) {
49         mSubtype = subtype;
50         mLocale = LocaleUtils.constructLocaleFromString(mSubtype.getLocale());
51     }
52 
53     // Extra values are determined by the primary subtype. This is probably right, but
54     // we may have to revisit this later.
getExtraValueOf(@onnull final String key)55     public String getExtraValueOf(@Nonnull final String key) {
56         return mSubtype.getExtraValueOf(key);
57     }
58 
59     // The mode is also determined by the primary subtype.
getMode()60     public String getMode() {
61         return mSubtype.getMode();
62     }
63 
isNoLanguage()64     public boolean isNoLanguage() {
65         return SubtypeLocaleUtils.NO_LANGUAGE.equals(mSubtype.getLocale());
66     }
67 
getNameForLogging()68     public String getNameForLogging() {
69         return toString();
70     }
71 
72     // InputMethodSubtype's display name for spacebar text in its locale.
73     //        isAdditionalSubtype (T=true, F=false)
74     // locale layout  |  Middle      Full
75     // ------ ------- - --------- ----------------------
76     //  en_US qwerty  F  English   English (US)           exception
77     //  en_GB qwerty  F  English   English (UK)           exception
78     //  es_US spanish F  Español   Español (EE.UU.)       exception
79     //  fr    azerty  F  Français  Français
80     //  fr_CA qwerty  F  Français  Français (Canada)
81     //  fr_CH swiss   F  Français  Français (Suisse)
82     //  de    qwertz  F  Deutsch   Deutsch
83     //  de_CH swiss   T  Deutsch   Deutsch (Schweiz)
84     //  zz    qwerty  F  QWERTY    QWERTY
85     //  fr    qwertz  T  Français  Français
86     //  de    qwerty  T  Deutsch   Deutsch
87     //  en_US azerty  T  English   English (US)
88     //  zz    azerty  T  AZERTY    AZERTY
89     // Get the RichInputMethodSubtype's full display name in its locale.
90     @Nonnull
getFullDisplayName()91     public String getFullDisplayName() {
92         if (isNoLanguage()) {
93             return SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(mSubtype);
94         }
95         return SubtypeLocaleUtils.getSubtypeLocaleDisplayName(mSubtype.getLocale());
96     }
97 
98     // Get the RichInputMethodSubtype's middle display name in its locale.
99     @Nonnull
getMiddleDisplayName()100     public String getMiddleDisplayName() {
101         if (isNoLanguage()) {
102             return SubtypeLocaleUtils.getKeyboardLayoutSetDisplayName(mSubtype);
103         }
104         return SubtypeLocaleUtils.getSubtypeLanguageDisplayName(mSubtype.getLocale());
105     }
106 
107     @Override
equals(final Object o)108     public boolean equals(final Object o) {
109         if (!(o instanceof RichInputMethodSubtype)) {
110             return false;
111         }
112         final RichInputMethodSubtype other = (RichInputMethodSubtype)o;
113         return mSubtype.equals(other.mSubtype) && mLocale.equals(other.mLocale);
114     }
115 
116     @Override
hashCode()117     public int hashCode() {
118         return mSubtype.hashCode() + mLocale.hashCode();
119     }
120 
121     @Override
toString()122     public String toString() {
123         return "Multi-lingual subtype: " + mSubtype + ", " + mLocale;
124     }
125 
126     @Nonnull
getLocale()127     public Locale getLocale() {
128         return mLocale;
129     }
130 
isRtlSubtype()131     public boolean isRtlSubtype() {
132         // The subtype is considered RTL if the language of the main subtype is RTL.
133         return LocaleUtils.isRtlLanguage(mLocale);
134     }
135 
136     // TODO: remove this method
137     @Nonnull
getRawSubtype()138     public InputMethodSubtype getRawSubtype() { return mSubtype; }
139 
140     @Nonnull
getKeyboardLayoutSetName()141     public String getKeyboardLayoutSetName() {
142         return SubtypeLocaleUtils.getKeyboardLayoutSetName(mSubtype);
143     }
144 
getRichInputMethodSubtype( @ullable final InputMethodSubtype subtype)145     public static RichInputMethodSubtype getRichInputMethodSubtype(
146             @Nullable final InputMethodSubtype subtype) {
147         if (subtype == null) {
148             return getNoLanguageSubtype();
149         } else {
150             return new RichInputMethodSubtype(subtype);
151         }
152     }
153 
154     // Dummy no language QWERTY subtype. See {@link R.xml.method}.
155     private static final int SUBTYPE_ID_OF_DUMMY_NO_LANGUAGE_SUBTYPE = 0xdde0bfd3;
156     private static final String EXTRA_VALUE_OF_DUMMY_NO_LANGUAGE_SUBTYPE =
157             "KeyboardLayoutSet=" + SubtypeLocaleUtils.QWERTY
158             + "," + Constants.Subtype.ExtraValue.ASCII_CAPABLE
159             + "," + Constants.Subtype.ExtraValue.ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE
160             + "," + Constants.Subtype.ExtraValue.EMOJI_CAPABLE;
161     @Nonnull
162     private static final RichInputMethodSubtype DUMMY_NO_LANGUAGE_SUBTYPE =
163             new RichInputMethodSubtype(InputMethodSubtypeCompatUtils.newInputMethodSubtype(
164                     R.string.subtype_no_language_qwerty, R.drawable.ic_ime_switcher_dark,
165                     SubtypeLocaleUtils.NO_LANGUAGE, KEYBOARD_MODE,
166                     EXTRA_VALUE_OF_DUMMY_NO_LANGUAGE_SUBTYPE,
167                     false /* isAuxiliary */, false /* overridesImplicitlyEnabledSubtype */,
168                     SUBTYPE_ID_OF_DUMMY_NO_LANGUAGE_SUBTYPE));
169     // Caveat: We probably should remove this when we add an Emoji subtype in {@link R.xml.method}.
170     // Dummy Emoji subtype. See {@link R.xml.method}.
171     private static final int SUBTYPE_ID_OF_DUMMY_EMOJI_SUBTYPE = 0xd78b2ed0;
172     private static final String EXTRA_VALUE_OF_DUMMY_EMOJI_SUBTYPE =
173             "KeyboardLayoutSet=" + SubtypeLocaleUtils.EMOJI
174             + "," + Constants.Subtype.ExtraValue.EMOJI_CAPABLE;
175     @Nonnull
176     private static final RichInputMethodSubtype DUMMY_EMOJI_SUBTYPE = new RichInputMethodSubtype(
177             InputMethodSubtypeCompatUtils.newInputMethodSubtype(
178                     R.string.subtype_emoji, R.drawable.ic_ime_switcher_dark,
179                     SubtypeLocaleUtils.NO_LANGUAGE, KEYBOARD_MODE,
180                     EXTRA_VALUE_OF_DUMMY_EMOJI_SUBTYPE,
181                     false /* isAuxiliary */, false /* overridesImplicitlyEnabledSubtype */,
182                     SUBTYPE_ID_OF_DUMMY_EMOJI_SUBTYPE));
183     private static RichInputMethodSubtype sNoLanguageSubtype;
184     private static RichInputMethodSubtype sEmojiSubtype;
185 
186     @Nonnull
getNoLanguageSubtype()187     public static RichInputMethodSubtype getNoLanguageSubtype() {
188         RichInputMethodSubtype noLanguageSubtype = sNoLanguageSubtype;
189         if (noLanguageSubtype == null) {
190             final InputMethodSubtype rawNoLanguageSubtype = RichInputMethodManager.getInstance()
191                     .findSubtypeByLocaleAndKeyboardLayoutSet(
192                             SubtypeLocaleUtils.NO_LANGUAGE, SubtypeLocaleUtils.QWERTY);
193             if (rawNoLanguageSubtype != null) {
194                 noLanguageSubtype = new RichInputMethodSubtype(rawNoLanguageSubtype);
195             }
196         }
197         if (noLanguageSubtype != null) {
198             sNoLanguageSubtype = noLanguageSubtype;
199             return noLanguageSubtype;
200         }
201         Log.w(TAG, "Can't find any language with QWERTY subtype");
202         Log.w(TAG, "No input method subtype found; returning dummy subtype: "
203                 + DUMMY_NO_LANGUAGE_SUBTYPE);
204         return DUMMY_NO_LANGUAGE_SUBTYPE;
205     }
206 
207     @Nonnull
getEmojiSubtype()208     public static RichInputMethodSubtype getEmojiSubtype() {
209         RichInputMethodSubtype emojiSubtype = sEmojiSubtype;
210         if (emojiSubtype == null) {
211             final InputMethodSubtype rawEmojiSubtype = RichInputMethodManager.getInstance()
212                     .findSubtypeByLocaleAndKeyboardLayoutSet(
213                             SubtypeLocaleUtils.NO_LANGUAGE, SubtypeLocaleUtils.EMOJI);
214             if (rawEmojiSubtype != null) {
215                 emojiSubtype = new RichInputMethodSubtype(rawEmojiSubtype);
216             }
217         }
218         if (emojiSubtype != null) {
219             sEmojiSubtype = emojiSubtype;
220             return emojiSubtype;
221         }
222         Log.w(TAG, "Can't find emoji subtype");
223         Log.w(TAG, "No input method subtype found; returning dummy subtype: "
224                 + DUMMY_EMOJI_SUBTYPE);
225         return DUMMY_EMOJI_SUBTYPE;
226     }
227 }
228