blob: fdd24a6b9e66519daadd208fef19beddbcd50ee7 [file] [log] [blame]
Satoshi Kataokad7443c82013-10-15 17:45:43 +09001/*
2 * Copyright (C) 2013 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
17package com.android.internal.inputmethod;
18
Satoshi Kataokad787f692013-10-26 04:44:21 +090019import android.content.Context;
20import android.content.pm.PackageManager;
21import android.text.TextUtils;
Yohei Yukawa9b29d042014-05-22 20:26:39 +090022import android.util.Log;
Satoshi Kataokad7443c82013-10-15 17:45:43 +090023import android.util.Slog;
24import android.view.inputmethod.InputMethodInfo;
25import android.view.inputmethod.InputMethodSubtype;
26
Yohei Yukawa40139402014-05-21 22:56:40 +090027import com.android.internal.annotations.VisibleForTesting;
28import com.android.internal.inputmethod.InputMethodUtils.InputMethodSettings;
29
Satoshi Kataokad787f692013-10-26 04:44:21 +090030import java.util.ArrayList;
31import java.util.Collections;
32import java.util.Comparator;
33import java.util.HashMap;
34import java.util.HashSet;
35import java.util.List;
36import java.util.Locale;
Yohei Yukawa07bd7322014-06-02 15:32:59 +090037import java.util.Objects;
Satoshi Kataokad787f692013-10-26 04:44:21 +090038import java.util.TreeMap;
Satoshi Kataokad7443c82013-10-15 17:45:43 +090039
40/**
41 * InputMethodSubtypeSwitchingController controls the switching behavior of the subtypes.
Yohei Yukawa5a647b692014-05-22 12:49:00 +090042 * <p>
43 * This class is designed to be used from and only from {@link InputMethodManagerService} by using
44 * {@link InputMethodManagerService#mMethodMap} as a global lock.
45 * </p>
Satoshi Kataokad7443c82013-10-15 17:45:43 +090046 */
47public class InputMethodSubtypeSwitchingController {
48 private static final String TAG = InputMethodSubtypeSwitchingController.class.getSimpleName();
49 private static final boolean DEBUG = false;
Satoshi Kataokad787f692013-10-26 04:44:21 +090050 private static final int NOT_A_SUBTYPE_ID = InputMethodUtils.NOT_A_SUBTYPE_ID;
51
Satoshi Kataokad787f692013-10-26 04:44:21 +090052 public static class ImeSubtypeListItem implements Comparable<ImeSubtypeListItem> {
53 public final CharSequence mImeName;
54 public final CharSequence mSubtypeName;
55 public final InputMethodInfo mImi;
56 public final int mSubtypeId;
57 private final boolean mIsSystemLocale;
58 private final boolean mIsSystemLanguage;
59
60 public ImeSubtypeListItem(CharSequence imeName, CharSequence subtypeName,
61 InputMethodInfo imi, int subtypeId, String subtypeLocale, String systemLocale) {
62 mImeName = imeName;
63 mSubtypeName = subtypeName;
64 mImi = imi;
65 mSubtypeId = subtypeId;
66 if (TextUtils.isEmpty(subtypeLocale)) {
67 mIsSystemLocale = false;
68 mIsSystemLanguage = false;
69 } else {
70 mIsSystemLocale = subtypeLocale.equals(systemLocale);
71 mIsSystemLanguage = mIsSystemLocale
72 || subtypeLocale.startsWith(systemLocale.substring(0, 2));
73 }
74 }
75
76 @Override
77 public int compareTo(ImeSubtypeListItem other) {
78 if (TextUtils.isEmpty(mImeName)) {
79 return 1;
80 }
81 if (TextUtils.isEmpty(other.mImeName)) {
82 return -1;
83 }
84 if (!TextUtils.equals(mImeName, other.mImeName)) {
85 return mImeName.toString().compareTo(other.mImeName.toString());
86 }
87 if (TextUtils.equals(mSubtypeName, other.mSubtypeName)) {
88 return 0;
89 }
90 if (mIsSystemLocale) {
91 return -1;
92 }
93 if (other.mIsSystemLocale) {
94 return 1;
95 }
96 if (mIsSystemLanguage) {
97 return -1;
98 }
99 if (other.mIsSystemLanguage) {
100 return 1;
101 }
102 if (TextUtils.isEmpty(mSubtypeName)) {
103 return 1;
104 }
105 if (TextUtils.isEmpty(other.mSubtypeName)) {
106 return -1;
107 }
108 return mSubtypeName.toString().compareTo(other.mSubtypeName.toString());
109 }
Yohei Yukawa1c630792014-05-22 15:55:24 +0900110
111 @Override
112 public String toString() {
113 return "ImeSubtypeListItem{"
114 + "mImeName=" + mImeName
115 + " mSubtypeName=" + mSubtypeName
116 + " mSubtypeId=" + mSubtypeId
117 + " mIsSystemLocale=" + mIsSystemLocale
118 + " mIsSystemLanguage=" + mIsSystemLanguage
119 + "}";
120 }
Yohei Yukawa07bd7322014-06-02 15:32:59 +0900121
122 @Override
123 public boolean equals(Object o) {
124 if (o == this) {
125 return true;
126 }
127 if (o instanceof ImeSubtypeListItem) {
128 final ImeSubtypeListItem that = (ImeSubtypeListItem)o;
129 if (!Objects.equals(this.mImi, that.mImi)) {
130 return false;
131 }
132 if (this.mSubtypeId != that.mSubtypeId) {
133 return false;
134 }
135 return true;
136 }
137 return false;
138 }
Satoshi Kataokad787f692013-10-26 04:44:21 +0900139 }
140
Yohei Yukawad1da1152014-05-01 17:20:05 +0900141 private static class InputMethodAndSubtypeList {
Satoshi Kataokad787f692013-10-26 04:44:21 +0900142 private final Context mContext;
143 // Used to load label
144 private final PackageManager mPm;
145 private final String mSystemLocaleStr;
146 private final InputMethodSettings mSettings;
147
Yohei Yukawad1da1152014-05-01 17:20:05 +0900148 public InputMethodAndSubtypeList(Context context, InputMethodSettings settings) {
Satoshi Kataokad787f692013-10-26 04:44:21 +0900149 mContext = context;
150 mSettings = settings;
151 mPm = context.getPackageManager();
152 final Locale locale = context.getResources().getConfiguration().locale;
153 mSystemLocaleStr = locale != null ? locale.toString() : "";
154 }
155
156 private final TreeMap<InputMethodInfo, List<InputMethodSubtype>> mSortedImmis =
157 new TreeMap<InputMethodInfo, List<InputMethodSubtype>>(
158 new Comparator<InputMethodInfo>() {
159 @Override
160 public int compare(InputMethodInfo imi1, InputMethodInfo imi2) {
161 if (imi2 == null)
162 return 0;
163 if (imi1 == null)
164 return 1;
165 if (mPm == null) {
166 return imi1.getId().compareTo(imi2.getId());
167 }
168 CharSequence imiId1 = imi1.loadLabel(mPm) + "/" + imi1.getId();
169 CharSequence imiId2 = imi2.loadLabel(mPm) + "/" + imi2.getId();
170 return imiId1.toString().compareTo(imiId2.toString());
171 }
172 });
173
Satoshi Kataokad787f692013-10-26 04:44:21 +0900174 public List<ImeSubtypeListItem> getSortedInputMethodAndSubtypeList() {
175 return getSortedInputMethodAndSubtypeList(true, false, false);
176 }
177
178 public List<ImeSubtypeListItem> getSortedInputMethodAndSubtypeList(
179 boolean showSubtypes, boolean inputShown, boolean isScreenLocked) {
180 final ArrayList<ImeSubtypeListItem> imList =
181 new ArrayList<ImeSubtypeListItem>();
182 final HashMap<InputMethodInfo, List<InputMethodSubtype>> immis =
183 mSettings.getExplicitlyOrImplicitlyEnabledInputMethodsAndSubtypeListLocked(
184 mContext);
185 if (immis == null || immis.size() == 0) {
186 return Collections.emptyList();
187 }
188 mSortedImmis.clear();
189 mSortedImmis.putAll(immis);
190 for (InputMethodInfo imi : mSortedImmis.keySet()) {
191 if (imi == null) {
192 continue;
193 }
194 List<InputMethodSubtype> explicitlyOrImplicitlyEnabledSubtypeList = immis.get(imi);
195 HashSet<String> enabledSubtypeSet = new HashSet<String>();
196 for (InputMethodSubtype subtype : explicitlyOrImplicitlyEnabledSubtypeList) {
197 enabledSubtypeSet.add(String.valueOf(subtype.hashCode()));
198 }
199 final CharSequence imeLabel = imi.loadLabel(mPm);
200 if (showSubtypes && enabledSubtypeSet.size() > 0) {
201 final int subtypeCount = imi.getSubtypeCount();
202 if (DEBUG) {
203 Slog.v(TAG, "Add subtypes: " + subtypeCount + ", " + imi.getId());
204 }
205 for (int j = 0; j < subtypeCount; ++j) {
206 final InputMethodSubtype subtype = imi.getSubtypeAt(j);
207 final String subtypeHashCode = String.valueOf(subtype.hashCode());
208 // We show all enabled IMEs and subtypes when an IME is shown.
209 if (enabledSubtypeSet.contains(subtypeHashCode)
210 && ((inputShown && !isScreenLocked) || !subtype.isAuxiliary())) {
211 final CharSequence subtypeLabel =
212 subtype.overridesImplicitlyEnabledSubtype() ? null : subtype
213 .getDisplayName(mContext, imi.getPackageName(),
214 imi.getServiceInfo().applicationInfo);
215 imList.add(new ImeSubtypeListItem(imeLabel,
216 subtypeLabel, imi, j, subtype.getLocale(), mSystemLocaleStr));
217
218 // Removing this subtype from enabledSubtypeSet because we no
219 // longer need to add an entry of this subtype to imList to avoid
220 // duplicated entries.
221 enabledSubtypeSet.remove(subtypeHashCode);
222 }
223 }
224 } else {
225 imList.add(new ImeSubtypeListItem(imeLabel, null, imi, NOT_A_SUBTYPE_ID, null,
226 mSystemLocaleStr));
227 }
228 }
229 Collections.sort(imList);
230 return imList;
231 }
232 }
233
Yohei Yukawa9b29d042014-05-22 20:26:39 +0900234 private static int calculateSubtypeId(InputMethodInfo imi, InputMethodSubtype subtype) {
235 return subtype != null ? InputMethodUtils.getSubtypeIdFromHashCode(imi,
236 subtype.hashCode()) : NOT_A_SUBTYPE_ID;
237 }
Yohei Yukawad1da1152014-05-01 17:20:05 +0900238
Yohei Yukawa9b29d042014-05-22 20:26:39 +0900239 private static class StaticRotationList {
240 private final List<ImeSubtypeListItem> mImeSubtypeList;
241 public StaticRotationList(final List<ImeSubtypeListItem> imeSubtypeList) {
242 mImeSubtypeList = imeSubtypeList;
Yohei Yukawad1da1152014-05-01 17:20:05 +0900243 }
Yohei Yukawa9b29d042014-05-22 20:26:39 +0900244
245 /**
246 * Returns the index of the specified input method and subtype in the given list.
247 * @param imi The {@link InputMethodInfo} to be searched.
248 * @param subtype The {@link InputMethodSubtype} to be searched. null if the input method
249 * does not have a subtype.
250 * @return The index in the given list. -1 if not found.
251 */
252 private int getIndex(InputMethodInfo imi, InputMethodSubtype subtype) {
253 final int currentSubtypeId = calculateSubtypeId(imi, subtype);
254 final int N = mImeSubtypeList.size();
255 for (int i = 0; i < N; ++i) {
256 final ImeSubtypeListItem isli = mImeSubtypeList.get(i);
257 // Skip until the current IME/subtype is found.
258 if (imi.equals(isli.mImi) && isli.mSubtypeId == currentSubtypeId) {
259 return i;
Yohei Yukawaa1223cf2014-05-01 20:26:41 +0900260 }
Yohei Yukawa9b29d042014-05-22 20:26:39 +0900261 }
262 return -1;
263 }
264
265 public ImeSubtypeListItem getNextInputMethodLocked(boolean onlyCurrentIme,
266 InputMethodInfo imi, InputMethodSubtype subtype) {
267 if (imi == null) {
268 return null;
269 }
270 if (mImeSubtypeList.size() <= 1) {
271 return null;
272 }
273 final int currentIndex = getIndex(imi, subtype);
274 if (currentIndex < 0) {
275 return null;
276 }
277 final int N = mImeSubtypeList.size();
278 for (int offset = 1; offset < N; ++offset) {
279 // Start searching the next IME/subtype from the next of the current index.
280 final int candidateIndex = (currentIndex + offset) % N;
281 final ImeSubtypeListItem candidate = mImeSubtypeList.get(candidateIndex);
Yohei Yukawaa1223cf2014-05-01 20:26:41 +0900282 // Skip if searching inside the current IME only, but the candidate is not
283 // the current IME.
Yohei Yukawa9b29d042014-05-22 20:26:39 +0900284 if (onlyCurrentIme && !imi.equals(candidate.mImi)) {
Yohei Yukawaa1223cf2014-05-01 20:26:41 +0900285 continue;
286 }
287 return candidate;
288 }
Yohei Yukawaa1223cf2014-05-01 20:26:41 +0900289 return null;
Yohei Yukawad1da1152014-05-01 17:20:05 +0900290 }
Yohei Yukawad1da1152014-05-01 17:20:05 +0900291 }
Satoshi Kataokad787f692013-10-26 04:44:21 +0900292
Yohei Yukawaa9bda772014-05-23 18:35:13 +0900293 private static class DynamicRotationList {
294 private static final String TAG = DynamicRotationList.class.getSimpleName();
295 private final List<ImeSubtypeListItem> mImeSubtypeList;
296 private final int[] mUsageHistoryOfSubtypeListItemIndex;
297
Yohei Yukawa07bd7322014-06-02 15:32:59 +0900298 private DynamicRotationList(final List<ImeSubtypeListItem> imeSubtypeListItems) {
Yohei Yukawaa9bda772014-05-23 18:35:13 +0900299 mImeSubtypeList = imeSubtypeListItems;
300 mUsageHistoryOfSubtypeListItemIndex = new int[mImeSubtypeList.size()];
301 final int N = mImeSubtypeList.size();
302 for (int i = 0; i < N; i++) {
303 mUsageHistoryOfSubtypeListItemIndex[i] = i;
304 }
305 }
306
307 /**
308 * Returns the index of the specified object in
309 * {@link #mUsageHistoryOfSubtypeListItemIndex}.
310 * <p>We call the index of {@link #mUsageHistoryOfSubtypeListItemIndex} as "Usage Rank"
311 * so as not to be confused with the index in {@link #mImeSubtypeList}.
312 * @return -1 when the specified item doesn't belong to {@link #mImeSubtypeList} actually.
313 */
314 private int getUsageRank(final InputMethodInfo imi, InputMethodSubtype subtype) {
315 final int currentSubtypeId = calculateSubtypeId(imi, subtype);
316 final int N = mUsageHistoryOfSubtypeListItemIndex.length;
317 for (int usageRank = 0; usageRank < N; usageRank++) {
318 final int subtypeListItemIndex = mUsageHistoryOfSubtypeListItemIndex[usageRank];
319 final ImeSubtypeListItem subtypeListItem =
320 mImeSubtypeList.get(subtypeListItemIndex);
321 if (subtypeListItem.mImi.equals(imi) &&
322 subtypeListItem.mSubtypeId == currentSubtypeId) {
323 return usageRank;
324 }
325 }
326 // Not found in the known IME/Subtype list.
327 return -1;
328 }
329
330 public void onUserAction(InputMethodInfo imi, InputMethodSubtype subtype) {
331 final int currentUsageRank = getUsageRank(imi, subtype);
332 // Do nothing if currentUsageRank == -1 (not found), or currentUsageRank == 0
333 if (currentUsageRank <= 0) {
334 return;
335 }
336 final int currentItemIndex = mUsageHistoryOfSubtypeListItemIndex[currentUsageRank];
337 System.arraycopy(mUsageHistoryOfSubtypeListItemIndex, 0,
338 mUsageHistoryOfSubtypeListItemIndex, 1, currentUsageRank);
339 mUsageHistoryOfSubtypeListItemIndex[0] = currentItemIndex;
340 }
341
342 public ImeSubtypeListItem getNextInputMethodLocked(boolean onlyCurrentIme,
343 InputMethodInfo imi, InputMethodSubtype subtype) {
344 int currentUsageRank = getUsageRank(imi, subtype);
345 if (currentUsageRank < 0) {
346 if (DEBUG) {
347 Slog.d(TAG, "IME/subtype is not found: " + imi.getId() + ", " + subtype);
348 }
349 return null;
350 }
351 final int N = mUsageHistoryOfSubtypeListItemIndex.length;
352 for (int i = 1; i < N; i++) {
353 final int subtypeListItemRank = (currentUsageRank + i) % N;
354 final int subtypeListItemIndex =
355 mUsageHistoryOfSubtypeListItemIndex[subtypeListItemRank];
356 final ImeSubtypeListItem subtypeListItem =
357 mImeSubtypeList.get(subtypeListItemIndex);
358 if (onlyCurrentIme && !imi.equals(subtypeListItem.mImi)) {
359 continue;
360 }
361 return subtypeListItem;
362 }
363 return null;
364 }
365 }
366
Yohei Yukawa9b29d042014-05-22 20:26:39 +0900367 @VisibleForTesting
368 public static class ControllerImpl {
Yohei Yukawa07bd7322014-06-02 15:32:59 +0900369 private final DynamicRotationList mSwitchingAwareRotationList;
370 private final StaticRotationList mSwitchingUnawareRotationList;
Yohei Yukawa9b29d042014-05-22 20:26:39 +0900371
Yohei Yukawa07bd7322014-06-02 15:32:59 +0900372 public static ControllerImpl createFrom(final ControllerImpl currentInstance,
373 final List<ImeSubtypeListItem> sortedEnabledItems) {
374 DynamicRotationList switchingAwareRotationList = null;
375 {
376 final List<ImeSubtypeListItem> switchingAwareImeSubtypes =
377 filterImeSubtypeList(sortedEnabledItems,
378 true /* supportsSwitchingToNextInputMethod */);
379 if (currentInstance != null &&
380 currentInstance.mSwitchingAwareRotationList != null &&
381 Objects.equals(currentInstance.mSwitchingAwareRotationList.mImeSubtypeList,
382 switchingAwareImeSubtypes)) {
383 // Can reuse the current instance.
384 switchingAwareRotationList = currentInstance.mSwitchingAwareRotationList;
385 }
386 if (switchingAwareRotationList == null) {
387 switchingAwareRotationList = new DynamicRotationList(switchingAwareImeSubtypes);
388 }
389 }
390
391 StaticRotationList switchingUnawareRotationList = null;
392 {
393 final List<ImeSubtypeListItem> switchingUnawareImeSubtypes = filterImeSubtypeList(
394 sortedEnabledItems, false /* supportsSwitchingToNextInputMethod */);
395 if (currentInstance != null &&
396 currentInstance.mSwitchingUnawareRotationList != null &&
397 Objects.equals(
398 currentInstance.mSwitchingUnawareRotationList.mImeSubtypeList,
399 switchingUnawareImeSubtypes)) {
400 // Can reuse the current instance.
401 switchingUnawareRotationList = currentInstance.mSwitchingUnawareRotationList;
402 }
403 if (switchingUnawareRotationList == null) {
404 switchingUnawareRotationList =
405 new StaticRotationList(switchingUnawareImeSubtypes);
406 }
407 }
408
409 return new ControllerImpl(switchingAwareRotationList, switchingUnawareRotationList);
410 }
411
412 private ControllerImpl(final DynamicRotationList switchingAwareRotationList,
413 final StaticRotationList switchingUnawareRotationList) {
414 mSwitchingAwareRotationList = switchingAwareRotationList;
415 mSwitchingUnawareRotationList = switchingUnawareRotationList;
Yohei Yukawa9b29d042014-05-22 20:26:39 +0900416 }
417
418 public ImeSubtypeListItem getNextInputMethod(boolean onlyCurrentIme, InputMethodInfo imi,
419 InputMethodSubtype subtype) {
420 if (imi == null) {
421 return null;
422 }
423 if (imi.supportsSwitchingToNextInputMethod()) {
Yohei Yukawa07bd7322014-06-02 15:32:59 +0900424 return mSwitchingAwareRotationList.getNextInputMethodLocked(onlyCurrentIme, imi,
Yohei Yukawa9b29d042014-05-22 20:26:39 +0900425 subtype);
426 } else {
Yohei Yukawa07bd7322014-06-02 15:32:59 +0900427 return mSwitchingUnawareRotationList.getNextInputMethodLocked(onlyCurrentIme, imi,
Yohei Yukawa9b29d042014-05-22 20:26:39 +0900428 subtype);
429 }
430 }
431
Yohei Yukawaa9bda772014-05-23 18:35:13 +0900432 public void onUserActionLocked(InputMethodInfo imi, InputMethodSubtype subtype) {
433 if (imi == null) {
434 return;
435 }
Yohei Yukawa07bd7322014-06-02 15:32:59 +0900436 if (imi.supportsSwitchingToNextInputMethod()) {
437 mSwitchingAwareRotationList.onUserAction(imi, subtype);
438 }
Yohei Yukawaa9bda772014-05-23 18:35:13 +0900439 }
440
Yohei Yukawa9b29d042014-05-22 20:26:39 +0900441 private static List<ImeSubtypeListItem> filterImeSubtypeList(
442 final List<ImeSubtypeListItem> items,
443 final boolean supportsSwitchingToNextInputMethod) {
444 final ArrayList<ImeSubtypeListItem> result = new ArrayList<>();
445 final int ALL_ITEMS_COUNT = items.size();
446 for (int i = 0; i < ALL_ITEMS_COUNT; i++) {
447 final ImeSubtypeListItem item = items.get(i);
448 if (item.mImi.supportsSwitchingToNextInputMethod() ==
449 supportsSwitchingToNextInputMethod) {
450 result.add(item);
451 }
452 }
453 return result;
454 }
455 }
456
457 private final InputMethodSettings mSettings;
458 private InputMethodAndSubtypeList mSubtypeList;
459 private ControllerImpl mController;
460
Yohei Yukawa5a647b692014-05-22 12:49:00 +0900461 private InputMethodSubtypeSwitchingController(InputMethodSettings settings, Context context) {
Satoshi Kataokad787f692013-10-26 04:44:21 +0900462 mSettings = settings;
Yohei Yukawa5a647b692014-05-22 12:49:00 +0900463 resetCircularListLocked(context);
464 }
465
466 public static InputMethodSubtypeSwitchingController createInstanceLocked(
467 InputMethodSettings settings, Context context) {
468 return new InputMethodSubtypeSwitchingController(settings, context);
Satoshi Kataokad787f692013-10-26 04:44:21 +0900469 }
Satoshi Kataokad7443c82013-10-15 17:45:43 +0900470
Yohei Yukawa02970512014-06-05 16:16:18 +0900471 public void onUserActionLocked(InputMethodInfo imi, InputMethodSubtype subtype) {
Yohei Yukawaa9bda772014-05-23 18:35:13 +0900472 if (mController == null) {
473 if (DEBUG) {
474 Log.e(TAG, "mController shouldn't be null.");
475 }
476 return;
477 }
478 mController.onUserActionLocked(imi, subtype);
Satoshi Kataokad7443c82013-10-15 17:45:43 +0900479 }
Satoshi Kataokad787f692013-10-26 04:44:21 +0900480
481 public void resetCircularListLocked(Context context) {
Yohei Yukawa5a647b692014-05-22 12:49:00 +0900482 mSubtypeList = new InputMethodAndSubtypeList(context, mSettings);
Yohei Yukawa07bd7322014-06-02 15:32:59 +0900483 mController = ControllerImpl.createFrom(mController,
484 mSubtypeList.getSortedInputMethodAndSubtypeList());
Satoshi Kataokad787f692013-10-26 04:44:21 +0900485 }
486
Yohei Yukawa9b29d042014-05-22 20:26:39 +0900487 public ImeSubtypeListItem getNextInputMethodLocked(boolean onlyCurrentIme, InputMethodInfo imi,
488 InputMethodSubtype subtype) {
489 if (mController == null) {
490 if (DEBUG) {
491 Log.e(TAG, "mController shouldn't be null.");
492 }
493 return null;
494 }
495 return mController.getNextInputMethod(onlyCurrentIme, imi, subtype);
Satoshi Kataokad787f692013-10-26 04:44:21 +0900496 }
497
Yohei Yukawa5a647b692014-05-22 12:49:00 +0900498 public List<ImeSubtypeListItem> getSortedInputMethodAndSubtypeListLocked(boolean showSubtypes,
Satoshi Kataokad787f692013-10-26 04:44:21 +0900499 boolean inputShown, boolean isScreenLocked) {
Yohei Yukawa5a647b692014-05-22 12:49:00 +0900500 return mSubtypeList.getSortedInputMethodAndSubtypeList(
501 showSubtypes, inputShown, isScreenLocked);
Satoshi Kataokad787f692013-10-26 04:44:21 +0900502 }
Satoshi Kataokad7443c82013-10-15 17:45:43 +0900503}