| /* |
| * Copyright (C) 2012 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.inputmethod.latin; |
| |
| import static com.android.inputmethod.latin.Constants.Subtype.KEYBOARD_MODE; |
| |
| import android.content.Context; |
| import android.content.SharedPreferences; |
| import android.os.IBinder; |
| import android.preference.PreferenceManager; |
| import android.view.inputmethod.InputMethodInfo; |
| import android.view.inputmethod.InputMethodManager; |
| import android.view.inputmethod.InputMethodSubtype; |
| |
| import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; |
| |
| import java.util.Collections; |
| import java.util.List; |
| |
| /** |
| * Enrichment class for InputMethodManager to simplify interaction and add functionality. |
| */ |
| public final class RichInputMethodManager { |
| private static final String TAG = RichInputMethodManager.class.getSimpleName(); |
| |
| private RichInputMethodManager() { |
| // This utility class is not publicly instantiable. |
| } |
| |
| private static final RichInputMethodManager sInstance = new RichInputMethodManager(); |
| |
| private InputMethodManagerCompatWrapper mImmWrapper; |
| private InputMethodInfo mInputMethodInfoOfThisIme; |
| |
| public static RichInputMethodManager getInstance() { |
| sInstance.checkInitialized(); |
| return sInstance; |
| } |
| |
| public static void init(final Context context) { |
| final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context); |
| sInstance.initInternal(context, prefs); |
| } |
| |
| private boolean isInitialized() { |
| return mImmWrapper != null; |
| } |
| |
| private void checkInitialized() { |
| if (!isInitialized()) { |
| throw new RuntimeException(TAG + " is used before initialization"); |
| } |
| } |
| |
| private void initInternal(final Context context, final SharedPreferences prefs) { |
| if (isInitialized()) { |
| return; |
| } |
| mImmWrapper = new InputMethodManagerCompatWrapper(context); |
| mInputMethodInfoOfThisIme = getInputMethodInfoOfThisIme(context); |
| |
| // Initialize additional subtypes. |
| SubtypeLocale.init(context); |
| final String prefAdditionalSubtypes = Settings.readPrefAdditionalSubtypes( |
| prefs, context.getResources()); |
| final InputMethodSubtype[] additionalSubtypes = |
| AdditionalSubtype.createAdditionalSubtypesArray(prefAdditionalSubtypes); |
| setAdditionalInputMethodSubtypes(additionalSubtypes); |
| } |
| |
| public InputMethodManager getInputMethodManager() { |
| checkInitialized(); |
| return mImmWrapper.mImm; |
| } |
| |
| private InputMethodInfo getInputMethodInfoOfThisIme(final Context context) { |
| final String packageName = context.getPackageName(); |
| for (final InputMethodInfo imi : mImmWrapper.mImm.getInputMethodList()) { |
| if (imi.getPackageName().equals(packageName)) { |
| return imi; |
| } |
| } |
| throw new RuntimeException("Input method id for " + packageName + " not found."); |
| } |
| |
| public boolean switchToNextInputMethod(final IBinder token, final boolean onlyCurrentIme) { |
| final boolean result = mImmWrapper.switchToNextInputMethod(token, onlyCurrentIme); |
| if (!result) { |
| mImmWrapper.mImm.switchToLastInputMethod(token); |
| return false; |
| } |
| return true; |
| } |
| |
| public InputMethodInfo getInputMethodInfoOfThisIme() { |
| return mInputMethodInfoOfThisIme; |
| } |
| |
| public String getInputMethodIdOfThisIme() { |
| return mInputMethodInfoOfThisIme.getId(); |
| } |
| |
| public boolean checkIfSubtypeBelongsToThisImeAndEnabled(final InputMethodSubtype subtype) { |
| return checkIfSubtypeBelongsToImeAndEnabled(mInputMethodInfoOfThisIme, subtype); |
| } |
| |
| public boolean checkIfSubtypeBelongsToThisImeAndImplicitlyEnabled( |
| final InputMethodSubtype subtype) { |
| final boolean subtypeEnabled = checkIfSubtypeBelongsToThisImeAndEnabled(subtype); |
| final boolean subtypeExplicitlyEnabled = checkIfSubtypeBelongsToList( |
| subtype, mImmWrapper.mImm.getEnabledInputMethodSubtypeList( |
| mInputMethodInfoOfThisIme, false /* allowsImplicitlySelectedSubtypes */)); |
| return subtypeEnabled && !subtypeExplicitlyEnabled; |
| } |
| |
| public boolean checkIfSubtypeBelongsToImeAndEnabled(final InputMethodInfo imi, |
| final InputMethodSubtype subtype) { |
| return checkIfSubtypeBelongsToList( |
| subtype, mImmWrapper.mImm.getEnabledInputMethodSubtypeList( |
| imi, true /* allowsImplicitlySelectedSubtypes */)); |
| } |
| |
| private static boolean checkIfSubtypeBelongsToList(final InputMethodSubtype subtype, |
| final List<InputMethodSubtype> subtypes) { |
| for (final InputMethodSubtype ims : subtypes) { |
| if (ims.equals(subtype)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| public boolean checkIfSubtypeBelongsToThisIme(final InputMethodSubtype subtype) { |
| final InputMethodInfo myImi = mInputMethodInfoOfThisIme; |
| final int count = myImi.getSubtypeCount(); |
| for (int i = 0; i < count; i++) { |
| final InputMethodSubtype ims = myImi.getSubtypeAt(i); |
| if (ims.equals(subtype)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| public InputMethodSubtype getCurrentInputMethodSubtype( |
| final InputMethodSubtype defaultSubtype) { |
| final InputMethodSubtype currentSubtype = mImmWrapper.mImm.getCurrentInputMethodSubtype(); |
| return (currentSubtype != null) ? currentSubtype : defaultSubtype; |
| } |
| |
| public boolean hasMultipleEnabledIMEsOrSubtypes(final boolean shouldIncludeAuxiliarySubtypes) { |
| final List<InputMethodInfo> enabledImis = mImmWrapper.mImm.getEnabledInputMethodList(); |
| return hasMultipleEnabledSubtypes(shouldIncludeAuxiliarySubtypes, enabledImis); |
| } |
| |
| public boolean hasMultipleEnabledSubtypesInThisIme( |
| final boolean shouldIncludeAuxiliarySubtypes) { |
| final List<InputMethodInfo> imiList = Collections.singletonList(mInputMethodInfoOfThisIme); |
| return hasMultipleEnabledSubtypes(shouldIncludeAuxiliarySubtypes, imiList); |
| } |
| |
| private boolean hasMultipleEnabledSubtypes(final boolean shouldIncludeAuxiliarySubtypes, |
| final List<InputMethodInfo> imiList) { |
| // Number of the filtered IMEs |
| int filteredImisCount = 0; |
| |
| for (InputMethodInfo imi : imiList) { |
| // We can return true immediately after we find two or more filtered IMEs. |
| if (filteredImisCount > 1) return true; |
| final List<InputMethodSubtype> subtypes = |
| mImmWrapper.mImm.getEnabledInputMethodSubtypeList(imi, true); |
| // IMEs that have no subtypes should be counted. |
| if (subtypes.isEmpty()) { |
| ++filteredImisCount; |
| continue; |
| } |
| |
| int auxCount = 0; |
| for (InputMethodSubtype subtype : subtypes) { |
| if (subtype.isAuxiliary()) { |
| ++auxCount; |
| } |
| } |
| final int nonAuxCount = subtypes.size() - auxCount; |
| |
| // IMEs that have one or more non-auxiliary subtypes should be counted. |
| // If shouldIncludeAuxiliarySubtypes is true, IMEs that have two or more auxiliary |
| // subtypes should be counted as well. |
| if (nonAuxCount > 0 || (shouldIncludeAuxiliarySubtypes && auxCount > 1)) { |
| ++filteredImisCount; |
| continue; |
| } |
| } |
| |
| if (filteredImisCount > 1) { |
| return true; |
| } |
| final List<InputMethodSubtype> subtypes = |
| mImmWrapper.mImm.getEnabledInputMethodSubtypeList(null, true); |
| int keyboardCount = 0; |
| // imm.getEnabledInputMethodSubtypeList(null, true) will return the current IME's |
| // both explicitly and implicitly enabled input method subtype. |
| // (The current IME should be LatinIME.) |
| for (InputMethodSubtype subtype : subtypes) { |
| if (KEYBOARD_MODE.equals(subtype.getMode())) { |
| ++keyboardCount; |
| } |
| } |
| return keyboardCount > 1; |
| } |
| |
| public InputMethodSubtype findSubtypeByLocaleAndKeyboardLayoutSet(final String localeString, |
| final String keyboardLayoutSetName) { |
| final InputMethodInfo myImi = mInputMethodInfoOfThisIme; |
| final int count = myImi.getSubtypeCount(); |
| for (int i = 0; i < count; i++) { |
| final InputMethodSubtype subtype = myImi.getSubtypeAt(i); |
| final String layoutName = SubtypeLocale.getKeyboardLayoutSetName(subtype); |
| if (localeString.equals(subtype.getLocale()) |
| && keyboardLayoutSetName.equals(layoutName)) { |
| return subtype; |
| } |
| } |
| return null; |
| } |
| |
| public void setInputMethodAndSubtype(final IBinder token, final InputMethodSubtype subtype) { |
| mImmWrapper.mImm.setInputMethodAndSubtype( |
| token, mInputMethodInfoOfThisIme.getId(), subtype); |
| } |
| |
| public void setAdditionalInputMethodSubtypes(final InputMethodSubtype[] subtypes) { |
| mImmWrapper.mImm.setAdditionalInputMethodSubtypes( |
| mInputMethodInfoOfThisIme.getId(), subtypes); |
| } |
| } |