1 /* 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 17 package com.android.server.inputmethod; 18 19 import android.annotation.Nullable; 20 import android.content.Context; 21 import android.content.pm.PackageManager; 22 import android.text.TextUtils; 23 import android.util.ArraySet; 24 import android.util.Log; 25 import android.util.Printer; 26 import android.util.Slog; 27 import android.view.inputmethod.InputMethodInfo; 28 import android.view.inputmethod.InputMethodSubtype; 29 30 import com.android.internal.annotations.VisibleForTesting; 31 import com.android.server.inputmethod.InputMethodUtils.InputMethodSettings; 32 33 import java.util.ArrayList; 34 import java.util.Collections; 35 import java.util.List; 36 import java.util.Locale; 37 import java.util.Objects; 38 39 /** 40 * InputMethodSubtypeSwitchingController controls the switching behavior of the subtypes. 41 * 42 * <p>This class is designed to be used from and only from {@link InputMethodManagerService} by 43 * using {@link InputMethodManagerService#mMethodMap} as a global lock.</p> 44 */ 45 final class InputMethodSubtypeSwitchingController { 46 private static final String TAG = InputMethodSubtypeSwitchingController.class.getSimpleName(); 47 private static final boolean DEBUG = false; 48 private static final int NOT_A_SUBTYPE_ID = InputMethodUtils.NOT_A_SUBTYPE_ID; 49 50 public static class ImeSubtypeListItem implements Comparable<ImeSubtypeListItem> { 51 public final CharSequence mImeName; 52 public final CharSequence mSubtypeName; 53 public final InputMethodInfo mImi; 54 public final int mSubtypeId; 55 public final boolean mIsSystemLocale; 56 public final boolean mIsSystemLanguage; 57 ImeSubtypeListItem(CharSequence imeName, CharSequence subtypeName, InputMethodInfo imi, int subtypeId, String subtypeLocale, String systemLocale)58 public ImeSubtypeListItem(CharSequence imeName, CharSequence subtypeName, 59 InputMethodInfo imi, int subtypeId, String subtypeLocale, String systemLocale) { 60 mImeName = imeName; 61 mSubtypeName = subtypeName; 62 mImi = imi; 63 mSubtypeId = subtypeId; 64 if (TextUtils.isEmpty(subtypeLocale)) { 65 mIsSystemLocale = false; 66 mIsSystemLanguage = false; 67 } else { 68 mIsSystemLocale = subtypeLocale.equals(systemLocale); 69 if (mIsSystemLocale) { 70 mIsSystemLanguage = true; 71 } else { 72 // TODO: Use Locale#getLanguage or Locale#toLanguageTag 73 final String systemLanguage = parseLanguageFromLocaleString(systemLocale); 74 final String subtypeLanguage = parseLanguageFromLocaleString(subtypeLocale); 75 mIsSystemLanguage = systemLanguage.length() >= 2 && 76 systemLanguage.equals(subtypeLanguage); 77 } 78 } 79 } 80 81 /** 82 * Returns the language component of a given locale string. 83 * TODO: Use {@link Locale#getLanguage()} instead. 84 */ parseLanguageFromLocaleString(final String locale)85 private static String parseLanguageFromLocaleString(final String locale) { 86 final int idx = locale.indexOf('_'); 87 if (idx < 0) { 88 return locale; 89 } else { 90 return locale.substring(0, idx); 91 } 92 } 93 compareNullableCharSequences(@ullable CharSequence c1, @Nullable CharSequence c2)94 private static int compareNullableCharSequences(@Nullable CharSequence c1, 95 @Nullable CharSequence c2) { 96 // For historical reasons, an empty text needs to put at the last. 97 final boolean empty1 = TextUtils.isEmpty(c1); 98 final boolean empty2 = TextUtils.isEmpty(c2); 99 if (empty1 || empty2) { 100 return (empty1 ? 1 : 0) - (empty2 ? 1 : 0); 101 } 102 return c1.toString().compareTo(c2.toString()); 103 } 104 105 /** 106 * Compares this object with the specified object for order. The fields of this class will 107 * be compared in the following order. 108 * <ol> 109 * <li>{@link #mImeName}</li> 110 * <li>{@link #mIsSystemLocale}</li> 111 * <li>{@link #mIsSystemLanguage}</li> 112 * <li>{@link #mSubtypeName}</li> 113 * <li>{@link #mImi} with {@link InputMethodInfo#getId()}</li> 114 * </ol> 115 * Note: this class has a natural ordering that is inconsistent with {@link #equals(Object). 116 * This method doesn't compare {@link #mSubtypeId} but {@link #equals(Object)} does. 117 * 118 * @param other the object to be compared. 119 * @return a negative integer, zero, or positive integer as this object is less than, equal 120 * to, or greater than the specified <code>other</code> object. 121 */ 122 @Override compareTo(ImeSubtypeListItem other)123 public int compareTo(ImeSubtypeListItem other) { 124 int result = compareNullableCharSequences(mImeName, other.mImeName); 125 if (result != 0) { 126 return result; 127 } 128 // Subtype that has the same locale of the system's has higher priority. 129 result = (mIsSystemLocale ? -1 : 0) - (other.mIsSystemLocale ? -1 : 0); 130 if (result != 0) { 131 return result; 132 } 133 // Subtype that has the same language of the system's has higher priority. 134 result = (mIsSystemLanguage ? -1 : 0) - (other.mIsSystemLanguage ? -1 : 0); 135 if (result != 0) { 136 return result; 137 } 138 result = compareNullableCharSequences(mSubtypeName, other.mSubtypeName); 139 if (result != 0) { 140 return result; 141 } 142 return mImi.getId().compareTo(other.mImi.getId()); 143 } 144 145 @Override toString()146 public String toString() { 147 return "ImeSubtypeListItem{" 148 + "mImeName=" + mImeName 149 + " mSubtypeName=" + mSubtypeName 150 + " mSubtypeId=" + mSubtypeId 151 + " mIsSystemLocale=" + mIsSystemLocale 152 + " mIsSystemLanguage=" + mIsSystemLanguage 153 + "}"; 154 } 155 156 @Override equals(Object o)157 public boolean equals(Object o) { 158 if (o == this) { 159 return true; 160 } 161 if (o instanceof ImeSubtypeListItem) { 162 final ImeSubtypeListItem that = (ImeSubtypeListItem)o; 163 return Objects.equals(this.mImi, that.mImi) && this.mSubtypeId == that.mSubtypeId; 164 } 165 return false; 166 } 167 } 168 169 private static class InputMethodAndSubtypeList { 170 private final Context mContext; 171 // Used to load label 172 private final PackageManager mPm; 173 private final String mSystemLocaleStr; 174 private final InputMethodSettings mSettings; 175 InputMethodAndSubtypeList(Context context, InputMethodSettings settings)176 public InputMethodAndSubtypeList(Context context, InputMethodSettings settings) { 177 mContext = context; 178 mSettings = settings; 179 mPm = context.getPackageManager(); 180 final Locale locale = context.getResources().getConfiguration().locale; 181 mSystemLocaleStr = locale != null ? locale.toString() : ""; 182 } 183 getSortedInputMethodAndSubtypeList( boolean includeAuxiliarySubtypes, boolean isScreenLocked)184 public List<ImeSubtypeListItem> getSortedInputMethodAndSubtypeList( 185 boolean includeAuxiliarySubtypes, boolean isScreenLocked) { 186 final ArrayList<InputMethodInfo> imis = mSettings.getEnabledInputMethodListLocked(); 187 if (imis.isEmpty()) { 188 return Collections.emptyList(); 189 } 190 if (isScreenLocked && includeAuxiliarySubtypes) { 191 if (DEBUG) { 192 Slog.w(TAG, "Auxiliary subtypes are not allowed to be shown in lock screen."); 193 } 194 includeAuxiliarySubtypes = false; 195 } 196 final ArrayList<ImeSubtypeListItem> imList = new ArrayList<>(); 197 final int numImes = imis.size(); 198 for (int i = 0; i < numImes; ++i) { 199 final InputMethodInfo imi = imis.get(i); 200 final List<InputMethodSubtype> explicitlyOrImplicitlyEnabledSubtypeList = 201 mSettings.getEnabledInputMethodSubtypeListLocked(mContext, imi, true); 202 final ArraySet<String> enabledSubtypeSet = new ArraySet<>(); 203 for (InputMethodSubtype subtype : explicitlyOrImplicitlyEnabledSubtypeList) { 204 enabledSubtypeSet.add(String.valueOf(subtype.hashCode())); 205 } 206 final CharSequence imeLabel = imi.loadLabel(mPm); 207 if (enabledSubtypeSet.size() > 0) { 208 final int subtypeCount = imi.getSubtypeCount(); 209 if (DEBUG) { 210 Slog.v(TAG, "Add subtypes: " + subtypeCount + ", " + imi.getId()); 211 } 212 for (int j = 0; j < subtypeCount; ++j) { 213 final InputMethodSubtype subtype = imi.getSubtypeAt(j); 214 final String subtypeHashCode = String.valueOf(subtype.hashCode()); 215 // We show all enabled IMEs and subtypes when an IME is shown. 216 if (enabledSubtypeSet.contains(subtypeHashCode) 217 && (includeAuxiliarySubtypes || !subtype.isAuxiliary())) { 218 final CharSequence subtypeLabel = 219 subtype.overridesImplicitlyEnabledSubtype() ? null : subtype 220 .getDisplayName(mContext, imi.getPackageName(), 221 imi.getServiceInfo().applicationInfo); 222 imList.add(new ImeSubtypeListItem(imeLabel, 223 subtypeLabel, imi, j, subtype.getLocale(), mSystemLocaleStr)); 224 225 // Removing this subtype from enabledSubtypeSet because we no 226 // longer need to add an entry of this subtype to imList to avoid 227 // duplicated entries. 228 enabledSubtypeSet.remove(subtypeHashCode); 229 } 230 } 231 } else { 232 imList.add(new ImeSubtypeListItem(imeLabel, null, imi, NOT_A_SUBTYPE_ID, null, 233 mSystemLocaleStr)); 234 } 235 } 236 Collections.sort(imList); 237 return imList; 238 } 239 } 240 calculateSubtypeId(InputMethodInfo imi, InputMethodSubtype subtype)241 private static int calculateSubtypeId(InputMethodInfo imi, InputMethodSubtype subtype) { 242 return subtype != null ? InputMethodUtils.getSubtypeIdFromHashCode(imi, 243 subtype.hashCode()) : NOT_A_SUBTYPE_ID; 244 } 245 246 private static class StaticRotationList { 247 private final List<ImeSubtypeListItem> mImeSubtypeList; StaticRotationList(final List<ImeSubtypeListItem> imeSubtypeList)248 public StaticRotationList(final List<ImeSubtypeListItem> imeSubtypeList) { 249 mImeSubtypeList = imeSubtypeList; 250 } 251 252 /** 253 * Returns the index of the specified input method and subtype in the given list. 254 * @param imi The {@link InputMethodInfo} to be searched. 255 * @param subtype The {@link InputMethodSubtype} to be searched. null if the input method 256 * does not have a subtype. 257 * @return The index in the given list. -1 if not found. 258 */ getIndex(InputMethodInfo imi, InputMethodSubtype subtype)259 private int getIndex(InputMethodInfo imi, InputMethodSubtype subtype) { 260 final int currentSubtypeId = calculateSubtypeId(imi, subtype); 261 final int N = mImeSubtypeList.size(); 262 for (int i = 0; i < N; ++i) { 263 final ImeSubtypeListItem isli = mImeSubtypeList.get(i); 264 // Skip until the current IME/subtype is found. 265 if (imi.equals(isli.mImi) && isli.mSubtypeId == currentSubtypeId) { 266 return i; 267 } 268 } 269 return -1; 270 } 271 getNextInputMethodLocked(boolean onlyCurrentIme, InputMethodInfo imi, InputMethodSubtype subtype)272 public ImeSubtypeListItem getNextInputMethodLocked(boolean onlyCurrentIme, 273 InputMethodInfo imi, InputMethodSubtype subtype) { 274 if (imi == null) { 275 return null; 276 } 277 if (mImeSubtypeList.size() <= 1) { 278 return null; 279 } 280 final int currentIndex = getIndex(imi, subtype); 281 if (currentIndex < 0) { 282 return null; 283 } 284 final int N = mImeSubtypeList.size(); 285 for (int offset = 1; offset < N; ++offset) { 286 // Start searching the next IME/subtype from the next of the current index. 287 final int candidateIndex = (currentIndex + offset) % N; 288 final ImeSubtypeListItem candidate = mImeSubtypeList.get(candidateIndex); 289 // Skip if searching inside the current IME only, but the candidate is not 290 // the current IME. 291 if (onlyCurrentIme && !imi.equals(candidate.mImi)) { 292 continue; 293 } 294 return candidate; 295 } 296 return null; 297 } 298 dump(final Printer pw, final String prefix)299 protected void dump(final Printer pw, final String prefix) { 300 final int N = mImeSubtypeList.size(); 301 for (int i = 0; i < N; ++i) { 302 final int rank = i; 303 final ImeSubtypeListItem item = mImeSubtypeList.get(i); 304 pw.println(prefix + "rank=" + rank + " item=" + item); 305 } 306 } 307 } 308 309 private static class DynamicRotationList { 310 private static final String TAG = DynamicRotationList.class.getSimpleName(); 311 private final List<ImeSubtypeListItem> mImeSubtypeList; 312 private final int[] mUsageHistoryOfSubtypeListItemIndex; 313 DynamicRotationList(final List<ImeSubtypeListItem> imeSubtypeListItems)314 private DynamicRotationList(final List<ImeSubtypeListItem> imeSubtypeListItems) { 315 mImeSubtypeList = imeSubtypeListItems; 316 mUsageHistoryOfSubtypeListItemIndex = new int[mImeSubtypeList.size()]; 317 final int N = mImeSubtypeList.size(); 318 for (int i = 0; i < N; i++) { 319 mUsageHistoryOfSubtypeListItemIndex[i] = i; 320 } 321 } 322 323 /** 324 * Returns the index of the specified object in 325 * {@link #mUsageHistoryOfSubtypeListItemIndex}. 326 * <p>We call the index of {@link #mUsageHistoryOfSubtypeListItemIndex} as "Usage Rank" 327 * so as not to be confused with the index in {@link #mImeSubtypeList}. 328 * @return -1 when the specified item doesn't belong to {@link #mImeSubtypeList} actually. 329 */ getUsageRank(final InputMethodInfo imi, InputMethodSubtype subtype)330 private int getUsageRank(final InputMethodInfo imi, InputMethodSubtype subtype) { 331 final int currentSubtypeId = calculateSubtypeId(imi, subtype); 332 final int N = mUsageHistoryOfSubtypeListItemIndex.length; 333 for (int usageRank = 0; usageRank < N; usageRank++) { 334 final int subtypeListItemIndex = mUsageHistoryOfSubtypeListItemIndex[usageRank]; 335 final ImeSubtypeListItem subtypeListItem = 336 mImeSubtypeList.get(subtypeListItemIndex); 337 if (subtypeListItem.mImi.equals(imi) && 338 subtypeListItem.mSubtypeId == currentSubtypeId) { 339 return usageRank; 340 } 341 } 342 // Not found in the known IME/Subtype list. 343 return -1; 344 } 345 onUserAction(InputMethodInfo imi, InputMethodSubtype subtype)346 public void onUserAction(InputMethodInfo imi, InputMethodSubtype subtype) { 347 final int currentUsageRank = getUsageRank(imi, subtype); 348 // Do nothing if currentUsageRank == -1 (not found), or currentUsageRank == 0 349 if (currentUsageRank <= 0) { 350 return; 351 } 352 final int currentItemIndex = mUsageHistoryOfSubtypeListItemIndex[currentUsageRank]; 353 System.arraycopy(mUsageHistoryOfSubtypeListItemIndex, 0, 354 mUsageHistoryOfSubtypeListItemIndex, 1, currentUsageRank); 355 mUsageHistoryOfSubtypeListItemIndex[0] = currentItemIndex; 356 } 357 getNextInputMethodLocked(boolean onlyCurrentIme, InputMethodInfo imi, InputMethodSubtype subtype)358 public ImeSubtypeListItem getNextInputMethodLocked(boolean onlyCurrentIme, 359 InputMethodInfo imi, InputMethodSubtype subtype) { 360 int currentUsageRank = getUsageRank(imi, subtype); 361 if (currentUsageRank < 0) { 362 if (DEBUG) { 363 Slog.d(TAG, "IME/subtype is not found: " + imi.getId() + ", " + subtype); 364 } 365 return null; 366 } 367 final int N = mUsageHistoryOfSubtypeListItemIndex.length; 368 for (int i = 1; i < N; i++) { 369 final int subtypeListItemRank = (currentUsageRank + i) % N; 370 final int subtypeListItemIndex = 371 mUsageHistoryOfSubtypeListItemIndex[subtypeListItemRank]; 372 final ImeSubtypeListItem subtypeListItem = 373 mImeSubtypeList.get(subtypeListItemIndex); 374 if (onlyCurrentIme && !imi.equals(subtypeListItem.mImi)) { 375 continue; 376 } 377 return subtypeListItem; 378 } 379 return null; 380 } 381 dump(final Printer pw, final String prefix)382 protected void dump(final Printer pw, final String prefix) { 383 for (int i = 0; i < mUsageHistoryOfSubtypeListItemIndex.length; ++i) { 384 final int rank = mUsageHistoryOfSubtypeListItemIndex[i]; 385 final ImeSubtypeListItem item = mImeSubtypeList.get(i); 386 pw.println(prefix + "rank=" + rank + " item=" + item); 387 } 388 } 389 } 390 391 @VisibleForTesting 392 public static class ControllerImpl { 393 private final DynamicRotationList mSwitchingAwareRotationList; 394 private final StaticRotationList mSwitchingUnawareRotationList; 395 createFrom(final ControllerImpl currentInstance, final List<ImeSubtypeListItem> sortedEnabledItems)396 public static ControllerImpl createFrom(final ControllerImpl currentInstance, 397 final List<ImeSubtypeListItem> sortedEnabledItems) { 398 DynamicRotationList switchingAwareRotationList = null; 399 { 400 final List<ImeSubtypeListItem> switchingAwareImeSubtypes = 401 filterImeSubtypeList(sortedEnabledItems, 402 true /* supportsSwitchingToNextInputMethod */); 403 if (currentInstance != null && 404 currentInstance.mSwitchingAwareRotationList != null && 405 Objects.equals(currentInstance.mSwitchingAwareRotationList.mImeSubtypeList, 406 switchingAwareImeSubtypes)) { 407 // Can reuse the current instance. 408 switchingAwareRotationList = currentInstance.mSwitchingAwareRotationList; 409 } 410 if (switchingAwareRotationList == null) { 411 switchingAwareRotationList = new DynamicRotationList(switchingAwareImeSubtypes); 412 } 413 } 414 415 StaticRotationList switchingUnawareRotationList = null; 416 { 417 final List<ImeSubtypeListItem> switchingUnawareImeSubtypes = filterImeSubtypeList( 418 sortedEnabledItems, false /* supportsSwitchingToNextInputMethod */); 419 if (currentInstance != null && 420 currentInstance.mSwitchingUnawareRotationList != null && 421 Objects.equals( 422 currentInstance.mSwitchingUnawareRotationList.mImeSubtypeList, 423 switchingUnawareImeSubtypes)) { 424 // Can reuse the current instance. 425 switchingUnawareRotationList = currentInstance.mSwitchingUnawareRotationList; 426 } 427 if (switchingUnawareRotationList == null) { 428 switchingUnawareRotationList = 429 new StaticRotationList(switchingUnawareImeSubtypes); 430 } 431 } 432 433 return new ControllerImpl(switchingAwareRotationList, switchingUnawareRotationList); 434 } 435 ControllerImpl(final DynamicRotationList switchingAwareRotationList, final StaticRotationList switchingUnawareRotationList)436 private ControllerImpl(final DynamicRotationList switchingAwareRotationList, 437 final StaticRotationList switchingUnawareRotationList) { 438 mSwitchingAwareRotationList = switchingAwareRotationList; 439 mSwitchingUnawareRotationList = switchingUnawareRotationList; 440 } 441 getNextInputMethod(boolean onlyCurrentIme, InputMethodInfo imi, InputMethodSubtype subtype)442 public ImeSubtypeListItem getNextInputMethod(boolean onlyCurrentIme, InputMethodInfo imi, 443 InputMethodSubtype subtype) { 444 if (imi == null) { 445 return null; 446 } 447 if (imi.supportsSwitchingToNextInputMethod()) { 448 return mSwitchingAwareRotationList.getNextInputMethodLocked(onlyCurrentIme, imi, 449 subtype); 450 } else { 451 return mSwitchingUnawareRotationList.getNextInputMethodLocked(onlyCurrentIme, imi, 452 subtype); 453 } 454 } 455 onUserActionLocked(InputMethodInfo imi, InputMethodSubtype subtype)456 public void onUserActionLocked(InputMethodInfo imi, InputMethodSubtype subtype) { 457 if (imi == null) { 458 return; 459 } 460 if (imi.supportsSwitchingToNextInputMethod()) { 461 mSwitchingAwareRotationList.onUserAction(imi, subtype); 462 } 463 } 464 filterImeSubtypeList( final List<ImeSubtypeListItem> items, final boolean supportsSwitchingToNextInputMethod)465 private static List<ImeSubtypeListItem> filterImeSubtypeList( 466 final List<ImeSubtypeListItem> items, 467 final boolean supportsSwitchingToNextInputMethod) { 468 final ArrayList<ImeSubtypeListItem> result = new ArrayList<>(); 469 final int ALL_ITEMS_COUNT = items.size(); 470 for (int i = 0; i < ALL_ITEMS_COUNT; i++) { 471 final ImeSubtypeListItem item = items.get(i); 472 if (item.mImi.supportsSwitchingToNextInputMethod() == 473 supportsSwitchingToNextInputMethod) { 474 result.add(item); 475 } 476 } 477 return result; 478 } 479 dump(final Printer pw)480 protected void dump(final Printer pw) { 481 pw.println(" mSwitchingAwareRotationList:"); 482 mSwitchingAwareRotationList.dump(pw, " "); 483 pw.println(" mSwitchingUnawareRotationList:"); 484 mSwitchingUnawareRotationList.dump(pw, " "); 485 } 486 } 487 488 private final InputMethodSettings mSettings; 489 private InputMethodAndSubtypeList mSubtypeList; 490 private ControllerImpl mController; 491 InputMethodSubtypeSwitchingController(InputMethodSettings settings, Context context)492 private InputMethodSubtypeSwitchingController(InputMethodSettings settings, Context context) { 493 mSettings = settings; 494 resetCircularListLocked(context); 495 } 496 createInstanceLocked( InputMethodSettings settings, Context context)497 public static InputMethodSubtypeSwitchingController createInstanceLocked( 498 InputMethodSettings settings, Context context) { 499 return new InputMethodSubtypeSwitchingController(settings, context); 500 } 501 onUserActionLocked(InputMethodInfo imi, InputMethodSubtype subtype)502 public void onUserActionLocked(InputMethodInfo imi, InputMethodSubtype subtype) { 503 if (mController == null) { 504 if (DEBUG) { 505 Log.e(TAG, "mController shouldn't be null."); 506 } 507 return; 508 } 509 mController.onUserActionLocked(imi, subtype); 510 } 511 resetCircularListLocked(Context context)512 public void resetCircularListLocked(Context context) { 513 mSubtypeList = new InputMethodAndSubtypeList(context, mSettings); 514 mController = ControllerImpl.createFrom(mController, 515 mSubtypeList.getSortedInputMethodAndSubtypeList( 516 false /* includeAuxiliarySubtypes */, false /* isScreenLocked */)); 517 } 518 getNextInputMethodLocked(boolean onlyCurrentIme, InputMethodInfo imi, InputMethodSubtype subtype)519 public ImeSubtypeListItem getNextInputMethodLocked(boolean onlyCurrentIme, InputMethodInfo imi, 520 InputMethodSubtype subtype) { 521 if (mController == null) { 522 if (DEBUG) { 523 Log.e(TAG, "mController shouldn't be null."); 524 } 525 return null; 526 } 527 return mController.getNextInputMethod(onlyCurrentIme, imi, subtype); 528 } 529 getSortedInputMethodAndSubtypeListLocked( boolean includingAuxiliarySubtypes, boolean isScreenLocked)530 public List<ImeSubtypeListItem> getSortedInputMethodAndSubtypeListLocked( 531 boolean includingAuxiliarySubtypes, boolean isScreenLocked) { 532 return mSubtypeList.getSortedInputMethodAndSubtypeList( 533 includingAuxiliarySubtypes, isScreenLocked); 534 } 535 dump(final Printer pw)536 public void dump(final Printer pw) { 537 if (mController != null) { 538 mController.dump(pw); 539 } else { 540 pw.println(" mController=null"); 541 } 542 } 543 } 544