1 /* 2 * Copyright (C) 2012 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.Constants.Subtype.KEYBOARD_MODE; 20 21 import android.content.Context; 22 import android.view.inputmethod.InputMethodInfo; 23 import android.view.inputmethod.InputMethodManager; 24 import android.view.inputmethod.InputMethodSubtype; 25 26 import java.util.Collections; 27 import java.util.List; 28 29 /** 30 * Utility class for Input Method Framework 31 */ 32 public class ImfUtils { ImfUtils()33 private ImfUtils() { 34 // This utility class is not publicly instantiable. 35 } 36 37 private static InputMethodManager sInputMethodManager; 38 getInputMethodManager(Context context)39 public static InputMethodManager getInputMethodManager(Context context) { 40 if (sInputMethodManager == null) { 41 sInputMethodManager = (InputMethodManager)context.getSystemService( 42 Context.INPUT_METHOD_SERVICE); 43 } 44 return sInputMethodManager; 45 } 46 47 private static InputMethodInfo sInputMethodInfoOfThisIme; 48 getInputMethodInfoOfThisIme(Context context)49 public static InputMethodInfo getInputMethodInfoOfThisIme(Context context) { 50 if (sInputMethodInfoOfThisIme == null) { 51 final InputMethodManager imm = getInputMethodManager(context); 52 final String packageName = context.getPackageName(); 53 for (final InputMethodInfo imi : imm.getInputMethodList()) { 54 if (imi.getPackageName().equals(packageName)) 55 return imi; 56 } 57 throw new RuntimeException("Can not find input method id for " + packageName); 58 } 59 return sInputMethodInfoOfThisIme; 60 } 61 getInputMethodIdOfThisIme(Context context)62 public static String getInputMethodIdOfThisIme(Context context) { 63 return getInputMethodInfoOfThisIme(context).getId(); 64 } 65 checkIfSubtypeBelongsToThisImeAndEnabled(Context context, InputMethodSubtype ims)66 public static boolean checkIfSubtypeBelongsToThisImeAndEnabled(Context context, 67 InputMethodSubtype ims) { 68 final InputMethodInfo myImi = getInputMethodInfoOfThisIme(context); 69 final InputMethodManager imm = getInputMethodManager(context); 70 // TODO: Cache all subtypes of this IME for optimization 71 final List<InputMethodSubtype> subtypes = imm.getEnabledInputMethodSubtypeList(myImi, true); 72 for (final InputMethodSubtype subtype : subtypes) { 73 if (subtype.equals(ims)) { 74 return true; 75 } 76 } 77 return false; 78 } 79 checkIfSubtypeBelongsToThisIme(Context context, InputMethodSubtype ims)80 public static boolean checkIfSubtypeBelongsToThisIme(Context context, 81 InputMethodSubtype ims) { 82 final InputMethodInfo myImi = getInputMethodInfoOfThisIme(context); 83 final int count = myImi.getSubtypeCount(); 84 for (int i = 0; i < count; i++) { 85 final InputMethodSubtype subtype = myImi.getSubtypeAt(i); 86 if (subtype.equals(ims)) { 87 return true; 88 } 89 } 90 return false; 91 } 92 hasMultipleEnabledIMEsOrSubtypes(Context context, final boolean shouldIncludeAuxiliarySubtypes)93 public static boolean hasMultipleEnabledIMEsOrSubtypes(Context context, 94 final boolean shouldIncludeAuxiliarySubtypes) { 95 final InputMethodManager imm = getInputMethodManager(context); 96 final List<InputMethodInfo> enabledImis = imm.getEnabledInputMethodList(); 97 return hasMultipleEnabledSubtypes(context, shouldIncludeAuxiliarySubtypes, enabledImis); 98 } 99 hasMultipleEnabledSubtypesInThisIme(Context context, final boolean shouldIncludeAuxiliarySubtypes)100 public static boolean hasMultipleEnabledSubtypesInThisIme(Context context, 101 final boolean shouldIncludeAuxiliarySubtypes) { 102 final InputMethodInfo myImi = getInputMethodInfoOfThisIme(context); 103 final List<InputMethodInfo> imiList = Collections.singletonList(myImi); 104 return hasMultipleEnabledSubtypes(context, shouldIncludeAuxiliarySubtypes, imiList); 105 } 106 hasMultipleEnabledSubtypes(Context context, final boolean shouldIncludeAuxiliarySubtypes, List<InputMethodInfo> imiList)107 private static boolean hasMultipleEnabledSubtypes(Context context, 108 final boolean shouldIncludeAuxiliarySubtypes, List<InputMethodInfo> imiList) { 109 final InputMethodManager imm = getInputMethodManager(context); 110 111 // Number of the filtered IMEs 112 int filteredImisCount = 0; 113 114 for (InputMethodInfo imi : imiList) { 115 // We can return true immediately after we find two or more filtered IMEs. 116 if (filteredImisCount > 1) return true; 117 final List<InputMethodSubtype> subtypes = 118 imm.getEnabledInputMethodSubtypeList(imi, true); 119 // IMEs that have no subtypes should be counted. 120 if (subtypes.isEmpty()) { 121 ++filteredImisCount; 122 continue; 123 } 124 125 int auxCount = 0; 126 for (InputMethodSubtype subtype : subtypes) { 127 if (subtype.isAuxiliary()) { 128 ++auxCount; 129 } 130 } 131 final int nonAuxCount = subtypes.size() - auxCount; 132 133 // IMEs that have one or more non-auxiliary subtypes should be counted. 134 // If shouldIncludeAuxiliarySubtypes is true, IMEs that have two or more auxiliary 135 // subtypes should be counted as well. 136 if (nonAuxCount > 0 || (shouldIncludeAuxiliarySubtypes && auxCount > 1)) { 137 ++filteredImisCount; 138 continue; 139 } 140 } 141 142 if (filteredImisCount > 1) { 143 return true; 144 } 145 final List<InputMethodSubtype> subtypes = imm.getEnabledInputMethodSubtypeList(null, true); 146 int keyboardCount = 0; 147 // imm.getEnabledInputMethodSubtypeList(null, true) will return the current IME's 148 // both explicitly and implicitly enabled input method subtype. 149 // (The current IME should be LatinIME.) 150 for (InputMethodSubtype subtype : subtypes) { 151 if (KEYBOARD_MODE.equals(subtype.getMode())) { 152 ++keyboardCount; 153 } 154 } 155 return keyboardCount > 1; 156 } 157 findSubtypeByLocaleAndKeyboardLayoutSet( Context context, String localeString, String keyboardLayoutSetName)158 public static InputMethodSubtype findSubtypeByLocaleAndKeyboardLayoutSet( 159 Context context, String localeString, String keyboardLayoutSetName) { 160 final InputMethodInfo imi = getInputMethodInfoOfThisIme(context); 161 final int count = imi.getSubtypeCount(); 162 for (int i = 0; i < count; i++) { 163 final InputMethodSubtype subtype = imi.getSubtypeAt(i); 164 final String layoutName = SubtypeLocale.getKeyboardLayoutSetName(subtype); 165 if (localeString.equals(subtype.getLocale()) 166 && keyboardLayoutSetName.equals(layoutName)) { 167 return subtype; 168 } 169 } 170 return null; 171 } 172 setAdditionalInputMethodSubtypes(Context context, InputMethodSubtype[] subtypes)173 public static void setAdditionalInputMethodSubtypes(Context context, 174 InputMethodSubtype[] subtypes) { 175 final InputMethodManager imm = getInputMethodManager(context); 176 final String imiId = getInputMethodIdOfThisIme(context); 177 imm.setAdditionalInputMethodSubtypes(imiId, subtypes); 178 } 179 } 180