blob: 30eb9390274c371478e586e2e145720625ac7b5c [file] [log] [blame]
/*
* Copyright (C) 2013 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 android.os;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodSubtype;
import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
import com.android.internal.inputmethod.InputMethodUtils;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
public class InputMethodTest extends InstrumentationTestCase {
private static final boolean IS_AUX = true;
private static final boolean IS_DEFAULT = true;
private static final boolean IS_AUTO = true;
private static final boolean IS_ASCII_CAPABLE = true;
private static final boolean IS_SYSTEM_READY = true;
private static final ArrayList<InputMethodSubtype> NO_SUBTYPE = null;
private static final Locale LOCALE_EN_US = new Locale("en", "US");
private static final Locale LOCALE_EN_GB = new Locale("en", "GB");
private static final Locale LOCALE_EN_IN = new Locale("en", "IN");
private static final Locale LOCALE_HI = new Locale("hi");
@SmallTest
public void testDefaultEnabledImesWithDefaultVoiceIme() throws Exception {
final Context context = getInstrumentation().getTargetContext();
final ArrayList<InputMethodInfo> imis = new ArrayList<InputMethodInfo>();
imis.add(createDefaultAutoDummyVoiceIme());
imis.add(createNonDefaultAutoDummyVoiceIme0());
imis.add(createNonDefaultAutoDummyVoiceIme1());
imis.add(createNonDefaultDummyVoiceIme2());
imis.add(createDefaultDummyLatinKeyboardIme());
imis.add(createNonDefaultDummyJaJPKeyboardIme());
imis.add(createNonDefaultDummyJaJPKeyboardImeWithoutSubtypes());
imis.add(createDefaultDummyHinglishKeyboardIme());
// locale: en_US, system: not ready
final ArrayList<InputMethodInfo> enabledImisForSystemNotReadyLocaleEnUs =
callGetDefaultEnabledImesUnderWithLocale(context, !IS_SYSTEM_READY, imis,
LOCALE_EN_US);
assertEquals(toSet("DummyDefaultAutoVoiceIme", "DummyDefaultEnKeyboardIme",
"DummyNonDefaultAutoVoiceIme0", "DummyNonDefaultAutoVoiceIme1",
"DummyDefaultHinglishKeyboardIme"),
getPackageNames(enabledImisForSystemNotReadyLocaleEnUs));
// locale: en_US, system: ready
final ArrayList<InputMethodInfo> enabledImisForSystemReadyLocaleEnUs =
callGetDefaultEnabledImesUnderWithLocale(context, IS_SYSTEM_READY, imis,
LOCALE_EN_US);
assertEquals(toSet("DummyDefaultAutoVoiceIme", "DummyDefaultEnKeyboardIme",
"DummyDefaultHinglishKeyboardIme"),
getPackageNames(enabledImisForSystemReadyLocaleEnUs));
// locale: en_GB, system: not ready
final ArrayList<InputMethodInfo> enabledImisForSystemNotReadyLocaleEnGB =
callGetDefaultEnabledImesUnderWithLocale(context, !IS_SYSTEM_READY, imis,
LOCALE_EN_GB);
assertEquals(toSet("DummyDefaultAutoVoiceIme", "DummyDefaultEnKeyboardIme",
"DummyNonDefaultAutoVoiceIme0", "DummyNonDefaultAutoVoiceIme1",
"DummyDefaultHinglishKeyboardIme"),
getPackageNames(enabledImisForSystemNotReadyLocaleEnGB));
// locale: en_GB, system: ready
final ArrayList<InputMethodInfo> enabledImisForSystemReadyLocaleEnGB =
callGetDefaultEnabledImesUnderWithLocale(context, IS_SYSTEM_READY, imis,
LOCALE_EN_GB);
assertEquals(toSet("DummyDefaultAutoVoiceIme", "DummyDefaultEnKeyboardIme",
"DummyDefaultHinglishKeyboardIme"),
getPackageNames(enabledImisForSystemReadyLocaleEnGB));
// locale: en_IN, system: not ready
final ArrayList<InputMethodInfo> enabledImisForSystemNotReadyLocaleEnIN =
callGetDefaultEnabledImesUnderWithLocale(context, !IS_SYSTEM_READY, imis,
LOCALE_EN_IN);
assertEquals(toSet("DummyDefaultAutoVoiceIme", "DummyDefaultEnKeyboardIme",
"DummyNonDefaultAutoVoiceIme0", "DummyNonDefaultAutoVoiceIme1",
"DummyDefaultHinglishKeyboardIme"),
getPackageNames(enabledImisForSystemNotReadyLocaleEnIN));
// locale: en_IN, system: ready
final ArrayList<InputMethodInfo> enabledImisForSystemReadyLocaleEnIN =
callGetDefaultEnabledImesUnderWithLocale(context, IS_SYSTEM_READY, imis,
LOCALE_EN_IN);
assertEquals(toSet("DummyDefaultAutoVoiceIme", "DummyDefaultEnKeyboardIme",
"DummyDefaultHinglishKeyboardIme"),
getPackageNames(enabledImisForSystemReadyLocaleEnIN));
// locale: hi, system: not ready
final ArrayList<InputMethodInfo> enabledImisForSystemNotReadyLocaleHi =
callGetDefaultEnabledImesUnderWithLocale(context, !IS_SYSTEM_READY, imis,
LOCALE_HI);
assertEquals(toSet("DummyDefaultAutoVoiceIme", "DummyDefaultEnKeyboardIme",
"DummyNonDefaultAutoVoiceIme0", "DummyNonDefaultAutoVoiceIme1",
"DummyDefaultHinglishKeyboardIme"),
getPackageNames(enabledImisForSystemNotReadyLocaleHi));
// locale: hi, system: ready
final ArrayList<InputMethodInfo> enabledImisForSystemReadyLocaleHi =
callGetDefaultEnabledImesUnderWithLocale(context, IS_SYSTEM_READY, imis,
LOCALE_HI);
assertEquals(toSet("DummyDefaultAutoVoiceIme", "DummyDefaultEnKeyboardIme",
"DummyNonDefaultAutoVoiceIme0", "DummyNonDefaultAutoVoiceIme1",
"DummyDefaultHinglishKeyboardIme"),
getPackageNames(enabledImisForSystemReadyLocaleHi));
}
@SmallTest
public void testDefaultEnabledImesWithOutDefaultVoiceIme() throws Exception {
final Context context = getInstrumentation().getTargetContext();
final ArrayList<InputMethodInfo> imis = new ArrayList<InputMethodInfo>();
imis.add(createNonDefaultAutoDummyVoiceIme0());
imis.add(createNonDefaultAutoDummyVoiceIme1());
imis.add(createNonDefaultDummyVoiceIme2());
imis.add(createDefaultDummyLatinKeyboardIme());
imis.add(createNonDefaultDummyJaJPKeyboardIme());
imis.add(createNonDefaultDummyJaJPKeyboardImeWithoutSubtypes());
imis.add(createDefaultDummyHinglishKeyboardIme());
// locale: en_US, system: not ready
final ArrayList<InputMethodInfo> enabledImisForSystemNotReadyLocaleEnUs =
callGetDefaultEnabledImesUnderWithLocale(context, !IS_SYSTEM_READY, imis,
LOCALE_EN_US);
assertEquals(toSet("DummyNonDefaultAutoVoiceIme0", "DummyNonDefaultAutoVoiceIme1",
"DummyDefaultEnKeyboardIme", "DummyDefaultHinglishKeyboardIme"),
getPackageNames(enabledImisForSystemNotReadyLocaleEnUs));
// locale: en_US, system: ready
final ArrayList<InputMethodInfo> enabledImisForSystemReadyLocaleEnUs =
callGetDefaultEnabledImesUnderWithLocale(context, IS_SYSTEM_READY, imis,
LOCALE_EN_US);
assertEquals(toSet("DummyNonDefaultAutoVoiceIme0", "DummyNonDefaultAutoVoiceIme1",
"DummyDefaultEnKeyboardIme", "DummyDefaultHinglishKeyboardIme"),
getPackageNames(enabledImisForSystemReadyLocaleEnUs));
// locale: en_GB, system: not ready
final ArrayList<InputMethodInfo> enabledImisForSystemNotReadyLocaleEnGB =
callGetDefaultEnabledImesUnderWithLocale(context, !IS_SYSTEM_READY, imis,
LOCALE_EN_GB);
assertEquals(toSet("DummyNonDefaultAutoVoiceIme0", "DummyNonDefaultAutoVoiceIme1",
"DummyDefaultEnKeyboardIme", "DummyDefaultHinglishKeyboardIme"),
getPackageNames(enabledImisForSystemNotReadyLocaleEnGB));
// locale: en_GB, system: ready
final ArrayList<InputMethodInfo> enabledImisForSystemReadyLocaleEnGB =
callGetDefaultEnabledImesUnderWithLocale(context, IS_SYSTEM_READY, imis,
LOCALE_EN_GB);
assertEquals(toSet("DummyNonDefaultAutoVoiceIme0", "DummyNonDefaultAutoVoiceIme1",
"DummyDefaultEnKeyboardIme", "DummyDefaultHinglishKeyboardIme"),
getPackageNames(enabledImisForSystemReadyLocaleEnGB));
// locale: en_IN, system: not ready
final ArrayList<InputMethodInfo> enabledImisForSystemNotReadyLocaleEnIN =
callGetDefaultEnabledImesUnderWithLocale(context, !IS_SYSTEM_READY, imis,
LOCALE_EN_IN);
assertEquals(toSet("DummyNonDefaultAutoVoiceIme0", "DummyNonDefaultAutoVoiceIme1",
"DummyDefaultEnKeyboardIme", "DummyDefaultHinglishKeyboardIme"),
getPackageNames(enabledImisForSystemNotReadyLocaleEnIN));
// locale: en_IN, system: ready
final ArrayList<InputMethodInfo> enabledImisForSystemReadyLocaleEnIN =
callGetDefaultEnabledImesUnderWithLocale(context, IS_SYSTEM_READY, imis,
LOCALE_EN_IN);
assertEquals(toSet("DummyNonDefaultAutoVoiceIme0", "DummyNonDefaultAutoVoiceIme1",
"DummyDefaultEnKeyboardIme", "DummyDefaultHinglishKeyboardIme"),
getPackageNames(enabledImisForSystemReadyLocaleEnIN));
// locale: hi, system: not ready
final ArrayList<InputMethodInfo> enabledImisForSystemNotReadyLocaleHi =
callGetDefaultEnabledImesUnderWithLocale(context, !IS_SYSTEM_READY, imis,
LOCALE_HI);
assertEquals(toSet("DummyNonDefaultAutoVoiceIme0", "DummyNonDefaultAutoVoiceIme1",
"DummyDefaultEnKeyboardIme", "DummyDefaultHinglishKeyboardIme"),
getPackageNames(enabledImisForSystemNotReadyLocaleHi));
// locale: hi, system: ready
final ArrayList<InputMethodInfo> enabledImisForSystemReadyLocaleHi =
callGetDefaultEnabledImesUnderWithLocale(context, IS_SYSTEM_READY, imis,
LOCALE_HI);
assertEquals(toSet("DummyNonDefaultAutoVoiceIme0", "DummyNonDefaultAutoVoiceIme1",
"DummyDefaultEnKeyboardIme", "DummyDefaultHinglishKeyboardIme"),
getPackageNames(enabledImisForSystemReadyLocaleHi));
}
@SmallTest
public void testParcelable() throws Exception {
final ArrayList<InputMethodInfo> originalList = new ArrayList<InputMethodInfo>();
originalList.add(createNonDefaultAutoDummyVoiceIme0());
originalList.add(createNonDefaultAutoDummyVoiceIme1());
originalList.add(createNonDefaultDummyVoiceIme2());
originalList.add(createDefaultDummyLatinKeyboardIme());
originalList.add(createNonDefaultDummyJaJPKeyboardIme());
originalList.add(createNonDefaultDummyJaJPKeyboardImeWithoutSubtypes());
final List<InputMethodInfo> clonedList = cloneViaParcel(originalList);
assertNotNull(clonedList);
final List<InputMethodInfo> clonedClonedList = cloneViaParcel(clonedList);
assertNotNull(clonedClonedList);
assertEquals(originalList, clonedList);
assertEquals(clonedList, clonedClonedList);
assertEquals(originalList.size(), clonedList.size());
assertEquals(clonedList.size(), clonedClonedList.size());
for (int imeIndex = 0; imeIndex < originalList.size(); ++imeIndex) {
verifyEquality(originalList.get(imeIndex), clonedList.get(imeIndex));
verifyEquality(clonedList.get(imeIndex), clonedClonedList.get(imeIndex));
}
}
private static List<InputMethodInfo> cloneViaParcel(final List<InputMethodInfo> list) {
Parcel p = null;
try {
p = Parcel.obtain();
p.writeTypedList(list);
p.setDataPosition(0);
return p.createTypedArrayList(InputMethodInfo.CREATOR);
} finally {
if (p != null) {
p.recycle();
}
}
}
private static ArrayList<InputMethodInfo> callGetDefaultEnabledImesUnderWithLocale(
final Context context, final boolean isSystemReady,
final ArrayList<InputMethodInfo> imis, final Locale locale) {
final Locale initialLocale = context.getResources().getConfiguration().locale;
try {
context.getResources().getConfiguration().setLocale(locale);
return InputMethodUtils.getDefaultEnabledImes(context, isSystemReady, imis);
} finally {
context.getResources().getConfiguration().setLocale(initialLocale);
}
}
@SafeVarargs
private static <T> HashSet<T> toSet(final T... xs) {
return new HashSet<T>(Arrays.asList(xs));
}
private HashSet<String> getPackageNames(final ArrayList<InputMethodInfo> imis) {
final HashSet<String> packageNames = new HashSet<>();
for (final InputMethodInfo imi : imis) {
final String actualPackageName = imi.getPackageName();
packageNames.add(actualPackageName);
}
return packageNames;
}
private static void verifyEquality(InputMethodInfo expected, InputMethodInfo actual) {
assertEquals(expected, actual);
assertEquals(expected.getSubtypeCount(), actual.getSubtypeCount());
for (int subtypeIndex = 0; subtypeIndex < expected.getSubtypeCount(); ++subtypeIndex) {
final InputMethodSubtype expectedSubtype = expected.getSubtypeAt(subtypeIndex);
final InputMethodSubtype actualSubtype = actual.getSubtypeAt(subtypeIndex);
assertEquals(expectedSubtype, actualSubtype);
assertEquals(expectedSubtype.hashCode(), actualSubtype.hashCode());
}
}
private static InputMethodInfo createDummyInputMethodInfo(String packageName, String name,
CharSequence label, boolean isAuxIme, boolean isDefault,
List<InputMethodSubtype> subtypes) {
final ResolveInfo ri = new ResolveInfo();
final ServiceInfo si = new ServiceInfo();
final ApplicationInfo ai = new ApplicationInfo();
ai.packageName = packageName;
ai.enabled = true;
ai.flags |= ApplicationInfo.FLAG_SYSTEM;
si.applicationInfo = ai;
si.enabled = true;
si.packageName = packageName;
si.name = name;
si.exported = true;
si.nonLocalizedLabel = label;
ri.serviceInfo = si;
return new InputMethodInfo(ri, isAuxIme, "", subtypes, 1, isDefault);
}
private static InputMethodSubtype createDummyInputMethodSubtype(String locale, String mode,
boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype,
boolean isAsciiCapable) {
return new InputMethodSubtypeBuilder()
.setSubtypeNameResId(0)
.setSubtypeIconResId(0)
.setSubtypeLocale(locale)
.setSubtypeMode(mode)
.setSubtypeExtraValue("")
.setIsAuxiliary(isAuxiliary)
.setOverridesImplicitlyEnabledSubtype(overridesImplicitlyEnabledSubtype)
.setIsAsciiCapable(isAsciiCapable)
.build();
}
private static InputMethodInfo createDefaultAutoDummyVoiceIme() {
final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
subtypes.add(createDummyInputMethodSubtype("auto", "voice", IS_AUX, IS_AUTO,
!IS_ASCII_CAPABLE));
subtypes.add(createDummyInputMethodSubtype("en_US", "voice", IS_AUX, !IS_AUTO,
!IS_ASCII_CAPABLE));
return createDummyInputMethodInfo("DummyDefaultAutoVoiceIme", "dummy.voice0",
"DummyVoice0", IS_AUX, IS_DEFAULT, subtypes);
}
private static InputMethodInfo createNonDefaultAutoDummyVoiceIme0() {
final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
subtypes.add(createDummyInputMethodSubtype("auto", "voice", IS_AUX, IS_AUTO,
!IS_ASCII_CAPABLE));
subtypes.add(createDummyInputMethodSubtype("en_US", "voice", IS_AUX, !IS_AUTO,
!IS_ASCII_CAPABLE));
return createDummyInputMethodInfo("DummyNonDefaultAutoVoiceIme0", "dummy.voice1",
"DummyVoice1", IS_AUX, !IS_DEFAULT, subtypes);
}
private static InputMethodInfo createNonDefaultAutoDummyVoiceIme1() {
final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
subtypes.add(createDummyInputMethodSubtype("auto", "voice", IS_AUX, IS_AUTO,
!IS_ASCII_CAPABLE));
subtypes.add(createDummyInputMethodSubtype("en_US", "voice", IS_AUX, !IS_AUTO,
!IS_ASCII_CAPABLE));
return createDummyInputMethodInfo("DummyNonDefaultAutoVoiceIme1", "dummy.voice2",
"DummyVoice2", IS_AUX, !IS_DEFAULT, subtypes);
}
private static InputMethodInfo createNonDefaultDummyVoiceIme2() {
final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
subtypes.add(createDummyInputMethodSubtype("en_US", "voice", IS_AUX, !IS_AUTO,
!IS_ASCII_CAPABLE));
return createDummyInputMethodInfo("DummyNonDefaultVoiceIme2", "dummy.voice3",
"DummyVoice3", IS_AUX, !IS_DEFAULT, subtypes);
}
private static InputMethodInfo createDefaultDummyLatinKeyboardIme() {
final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
subtypes.add(createDummyInputMethodSubtype("en_US", "keyboard", !IS_AUX, !IS_AUTO,
IS_ASCII_CAPABLE));
subtypes.add(createDummyInputMethodSubtype("en_GB", "keyboard", !IS_AUX, !IS_AUTO,
IS_ASCII_CAPABLE));
subtypes.add(createDummyInputMethodSubtype("en_IN", "keyboard", !IS_AUX, !IS_AUTO,
IS_ASCII_CAPABLE));
subtypes.add(createDummyInputMethodSubtype("hi", "keyboard", !IS_AUX, !IS_AUTO,
!IS_ASCII_CAPABLE)); // not AsciiCapable!
subtypes.add(createDummyInputMethodSubtype("hi_ZZ", "keyboard", !IS_AUX, !IS_AUTO,
IS_ASCII_CAPABLE));
return createDummyInputMethodInfo("DummyDefaultEnKeyboardIme", "dummy.keyboard0",
"DummyKeyboard0", !IS_AUX, IS_DEFAULT, subtypes);
}
private static InputMethodInfo createNonDefaultDummyJaJPKeyboardIme() {
final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
subtypes.add(createDummyInputMethodSubtype("ja_JP", "keyboard", !IS_AUX, !IS_AUTO,
IS_ASCII_CAPABLE));
return createDummyInputMethodInfo("DummyNonDefaultJaJPKeyboardIme", "dummy.keyboard1",
"DummyKeyboard1", !IS_AUX, !IS_DEFAULT, subtypes);
}
// Although IMEs that have no subtype are considered to be deprecated, the Android framework
// must still be able to handle such IMEs as well as IMEs that have at least one subtype.
private static InputMethodInfo createNonDefaultDummyJaJPKeyboardImeWithoutSubtypes() {
final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
return createDummyInputMethodInfo("DummyNonDefaultJaJPKeyboardImeWithoutSubtypes",
"dummy.keyboard2", "DummyKeyboard2", !IS_AUX, !IS_DEFAULT, NO_SUBTYPE);
}
private static InputMethodInfo createDefaultDummyHinglishKeyboardIme() {
final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
subtypes.add(createDummyInputMethodSubtype("en_IN", "keyboard", !IS_AUX, !IS_AUTO,
IS_ASCII_CAPABLE));
subtypes.add(createDummyInputMethodSubtype("hi", "keyboard", !IS_AUX, !IS_AUTO,
!IS_ASCII_CAPABLE)); // not AsciiCapable!
return createDummyInputMethodInfo("DummyDefaultHinglishKeyboardIme", "dummy.keyboard2",
"DummyKeyboard2", !IS_AUX, IS_DEFAULT, subtypes);
}
}