| /* |
| * Copyright (C) 2014 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.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.InputMethodSubtypeSwitchingController.ControllerImpl; |
| import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem; |
| import com.android.internal.inputmethod.InputMethodUtils; |
| |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.List; |
| |
| public class InputMethodSubtypeSwitchingControllerTest extends InstrumentationTestCase { |
| private static final String DUMMY_PACKAGE_NAME = "dymmy package name"; |
| private static final String DUMMY_SETTING_ACTIVITY_NAME = ""; |
| private static final boolean DUMMY_IS_AUX_IME = false; |
| private static final boolean DUMMY_FORCE_DEFAULT = false; |
| private static final int DUMMY_IS_DEFAULT_RES_ID = 0; |
| private static final String SYSTEM_LOCALE = "en_US"; |
| private static final int NOT_A_SUBTYPE_ID = InputMethodUtils.NOT_A_SUBTYPE_ID; |
| |
| private static InputMethodSubtype createDummySubtype(final String locale) { |
| final InputMethodSubtypeBuilder builder = new InputMethodSubtypeBuilder(); |
| return builder.setSubtypeNameResId(0) |
| .setSubtypeIconResId(0) |
| .setSubtypeLocale(locale) |
| .setIsAsciiCapable(true) |
| .build(); |
| } |
| |
| private static void addDummyImeSubtypeListItems(List<ImeSubtypeListItem> items, |
| String imeName, String imeLabel, List<String> subtypeLocales, |
| boolean supportsSwitchingToNextInputMethod) { |
| final ResolveInfo ri = new ResolveInfo(); |
| final ServiceInfo si = new ServiceInfo(); |
| final ApplicationInfo ai = new ApplicationInfo(); |
| ai.packageName = DUMMY_PACKAGE_NAME; |
| ai.enabled = true; |
| si.applicationInfo = ai; |
| si.enabled = true; |
| si.packageName = DUMMY_PACKAGE_NAME; |
| si.name = imeName; |
| si.exported = true; |
| si.nonLocalizedLabel = imeLabel; |
| ri.serviceInfo = si; |
| List<InputMethodSubtype> subtypes = null; |
| if (subtypeLocales != null) { |
| subtypes = new ArrayList<InputMethodSubtype>(); |
| for (String subtypeLocale : subtypeLocales) { |
| subtypes.add(createDummySubtype(subtypeLocale)); |
| } |
| } |
| final InputMethodInfo imi = new InputMethodInfo(ri, DUMMY_IS_AUX_IME, |
| DUMMY_SETTING_ACTIVITY_NAME, subtypes, DUMMY_IS_DEFAULT_RES_ID, |
| DUMMY_FORCE_DEFAULT, supportsSwitchingToNextInputMethod); |
| if (subtypes == null) { |
| items.add(new ImeSubtypeListItem(imeName, null /* variableName */, imi, |
| NOT_A_SUBTYPE_ID, null, SYSTEM_LOCALE)); |
| } else { |
| for (int i = 0; i < subtypes.size(); ++i) { |
| final String subtypeLocale = subtypeLocales.get(i); |
| items.add(new ImeSubtypeListItem(imeName, subtypeLocale, imi, i, subtypeLocale, |
| SYSTEM_LOCALE)); |
| } |
| } |
| } |
| |
| private static List<ImeSubtypeListItem> createEnabledImeSubtypes() { |
| final List<ImeSubtypeListItem> items = new ArrayList<ImeSubtypeListItem>(); |
| addDummyImeSubtypeListItems(items, "LatinIme", "LatinIme", Arrays.asList("en_US", "fr"), |
| true /* supportsSwitchingToNextInputMethod*/); |
| addDummyImeSubtypeListItems(items, "switchUnawareLatinIme", "switchUnawareLatinIme", |
| Arrays.asList("en_UK", "hi"), |
| false /* supportsSwitchingToNextInputMethod*/); |
| addDummyImeSubtypeListItems(items, "subtypeUnawareIme", "subtypeUnawareIme", null, |
| false /* supportsSwitchingToNextInputMethod*/); |
| addDummyImeSubtypeListItems(items, "JapaneseIme", "JapaneseIme", Arrays.asList("ja_JP"), |
| true /* supportsSwitchingToNextInputMethod*/); |
| addDummyImeSubtypeListItems(items, "switchUnawareJapaneseIme", "switchUnawareJapaneseIme", |
| Arrays.asList("ja_JP"), false /* supportsSwitchingToNextInputMethod*/); |
| return items; |
| } |
| |
| private static List<ImeSubtypeListItem> createDisabledImeSubtypes() { |
| final List<ImeSubtypeListItem> items = new ArrayList<ImeSubtypeListItem>(); |
| addDummyImeSubtypeListItems(items, |
| "UnknownIme", "UnknownIme", |
| Arrays.asList("en_US", "hi"), |
| true /* supportsSwitchingToNextInputMethod*/); |
| addDummyImeSubtypeListItems(items, |
| "UnknownSwitchingUnawareIme", "UnknownSwitchingUnawareIme", |
| Arrays.asList("en_US"), |
| false /* supportsSwitchingToNextInputMethod*/); |
| addDummyImeSubtypeListItems(items, "UnknownSubtypeUnawareIme", |
| "UnknownSubtypeUnawareIme", null, |
| false /* supportsSwitchingToNextInputMethod*/); |
| return items; |
| } |
| |
| private void assertNextInputMethod(final ControllerImpl controller, |
| final boolean onlyCurrentIme, |
| final ImeSubtypeListItem currentItem, final ImeSubtypeListItem nextItem) { |
| InputMethodSubtype subtype = null; |
| if (currentItem.mSubtypeName != null) { |
| subtype = createDummySubtype(currentItem.mSubtypeName.toString()); |
| } |
| final ImeSubtypeListItem nextIme = controller.getNextInputMethod(onlyCurrentIme, |
| currentItem.mImi, subtype); |
| assertEquals(nextItem, nextIme); |
| } |
| |
| private void assertRotationOrder(final ControllerImpl controller, |
| final boolean onlyCurrentIme, |
| final ImeSubtypeListItem... expectedRotationOrderOfImeSubtypeList) { |
| final int N = expectedRotationOrderOfImeSubtypeList.length; |
| for (int i = 0; i < N; i++) { |
| final int currentIndex = i; |
| final int nextIndex = (currentIndex + 1) % N; |
| final ImeSubtypeListItem currentItem = |
| expectedRotationOrderOfImeSubtypeList[currentIndex]; |
| final ImeSubtypeListItem nextItem = expectedRotationOrderOfImeSubtypeList[nextIndex]; |
| assertNextInputMethod(controller, onlyCurrentIme, currentItem, nextItem); |
| } |
| } |
| |
| private void onUserAction(final ControllerImpl controller, |
| final ImeSubtypeListItem subtypeListItem) { |
| InputMethodSubtype subtype = null; |
| if (subtypeListItem.mSubtypeName != null) { |
| subtype = createDummySubtype(subtypeListItem.mSubtypeName.toString()); |
| } |
| controller.onUserActionLocked(subtypeListItem.mImi, subtype); |
| } |
| |
| @SmallTest |
| public void testControllerImpl() throws Exception { |
| final List<ImeSubtypeListItem> disabledItems = createDisabledImeSubtypes(); |
| final ImeSubtypeListItem disabledIme_en_US = disabledItems.get(0); |
| final ImeSubtypeListItem disabledIme_hi = disabledItems.get(1); |
| final ImeSubtypeListItem disabledSwitchingUnawareIme = disabledItems.get(2); |
| final ImeSubtypeListItem disabledSubtypeUnawareIme = disabledItems.get(3); |
| |
| final List<ImeSubtypeListItem> enabledItems = createEnabledImeSubtypes(); |
| final ImeSubtypeListItem latinIme_en_US = enabledItems.get(0); |
| final ImeSubtypeListItem latinIme_fr = enabledItems.get(1); |
| final ImeSubtypeListItem switchingUnawarelatinIme_en_UK = enabledItems.get(2); |
| final ImeSubtypeListItem switchingUnawarelatinIme_hi = enabledItems.get(3); |
| final ImeSubtypeListItem subtypeUnawareIme = enabledItems.get(4); |
| final ImeSubtypeListItem japaneseIme_ja_JP = enabledItems.get(5); |
| final ImeSubtypeListItem switchUnawareJapaneseIme_ja_JP = enabledItems.get(6); |
| |
| final ControllerImpl controller = new ControllerImpl(enabledItems); |
| |
| // switching-aware loop |
| assertRotationOrder(controller, false /* onlyCurrentIme */, |
| latinIme_en_US, latinIme_fr, japaneseIme_ja_JP); |
| |
| // switching-unaware loop |
| assertRotationOrder(controller, false /* onlyCurrentIme */, |
| switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi, subtypeUnawareIme, |
| switchUnawareJapaneseIme_ja_JP); |
| |
| // test onlyCurrentIme == true |
| assertRotationOrder(controller, true /* onlyCurrentIme */, |
| latinIme_en_US, latinIme_fr); |
| assertRotationOrder(controller, true /* onlyCurrentIme */, |
| switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi); |
| assertNextInputMethod(controller, true /* onlyCurrentIme */, |
| subtypeUnawareIme, null); |
| assertNextInputMethod(controller, true /* onlyCurrentIme */, |
| japaneseIme_ja_JP, null); |
| assertNextInputMethod(controller, true /* onlyCurrentIme */, |
| switchUnawareJapaneseIme_ja_JP, null); |
| |
| // Make sure that disabled IMEs are not accepted. |
| assertNextInputMethod(controller, false /* onlyCurrentIme */, |
| disabledIme_en_US, null); |
| assertNextInputMethod(controller, false /* onlyCurrentIme */, |
| disabledIme_hi, null); |
| assertNextInputMethod(controller, false /* onlyCurrentIme */, |
| disabledSwitchingUnawareIme, null); |
| assertNextInputMethod(controller, false /* onlyCurrentIme */, |
| disabledSubtypeUnawareIme, null); |
| assertNextInputMethod(controller, true /* onlyCurrentIme */, |
| disabledIme_en_US, null); |
| assertNextInputMethod(controller, true /* onlyCurrentIme */, |
| disabledIme_hi, null); |
| assertNextInputMethod(controller, true /* onlyCurrentIme */, |
| disabledSwitchingUnawareIme, null); |
| assertNextInputMethod(controller, true /* onlyCurrentIme */, |
| disabledSubtypeUnawareIme, null); |
| } |
| |
| // This test is disabled until DynamicRotationList is enabled. |
| @SmallTest |
| public void DISABLED_testControllerImplWithUserAction() throws Exception { |
| final List<ImeSubtypeListItem> enabledItems = createEnabledImeSubtypes(); |
| final ImeSubtypeListItem latinIme_en_US = enabledItems.get(0); |
| final ImeSubtypeListItem latinIme_fr = enabledItems.get(1); |
| final ImeSubtypeListItem switchingUnawarelatinIme_en_UK = enabledItems.get(2); |
| final ImeSubtypeListItem switchingUnawarelatinIme_hi = enabledItems.get(3); |
| final ImeSubtypeListItem subtypeUnawareIme = enabledItems.get(4); |
| final ImeSubtypeListItem japaneseIme_ja_JP = enabledItems.get(5); |
| final ImeSubtypeListItem switchUnawareJapaneseIme_ja_JP = enabledItems.get(6); |
| |
| final ControllerImpl controller = new ControllerImpl(enabledItems); |
| |
| // === switching-aware loop === |
| assertRotationOrder(controller, false /* onlyCurrentIme */, |
| latinIme_en_US, latinIme_fr, japaneseIme_ja_JP); |
| // Then notify that a user did something for latinIme_fr. |
| onUserAction(controller, latinIme_fr); |
| assertRotationOrder(controller, false /* onlyCurrentIme */, |
| latinIme_fr, latinIme_en_US, japaneseIme_ja_JP); |
| // Then notify that a user did something for latinIme_fr again. |
| onUserAction(controller, latinIme_fr); |
| assertRotationOrder(controller, false /* onlyCurrentIme */, |
| latinIme_fr, latinIme_en_US, japaneseIme_ja_JP); |
| // Then notify that a user did something for japaneseIme_ja_JP. |
| onUserAction(controller, latinIme_fr); |
| assertRotationOrder(controller, false /* onlyCurrentIme */, |
| japaneseIme_ja_JP, latinIme_fr, latinIme_en_US); |
| // Check onlyCurrentIme == true. |
| assertNextInputMethod(controller, true /* onlyCurrentIme */, |
| japaneseIme_ja_JP, null); |
| assertRotationOrder(controller, true /* onlyCurrentIme */, |
| latinIme_fr, latinIme_en_US); |
| assertRotationOrder(controller, true /* onlyCurrentIme */, |
| latinIme_en_US, latinIme_fr); |
| |
| // === switching-unaware loop === |
| assertRotationOrder(controller, false /* onlyCurrentIme */, |
| switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi, subtypeUnawareIme, |
| switchUnawareJapaneseIme_ja_JP); |
| // User action should be ignored for switching unaware IMEs. |
| onUserAction(controller, switchingUnawarelatinIme_hi); |
| assertRotationOrder(controller, false /* onlyCurrentIme */, |
| switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi, subtypeUnawareIme, |
| switchUnawareJapaneseIme_ja_JP); |
| // User action should be ignored for switching unaware IMEs. |
| onUserAction(controller, switchUnawareJapaneseIme_ja_JP); |
| assertRotationOrder(controller, false /* onlyCurrentIme */, |
| switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi, subtypeUnawareIme, |
| switchUnawareJapaneseIme_ja_JP); |
| // Check onlyCurrentIme == true. |
| assertRotationOrder(controller, true /* onlyCurrentIme */, |
| switchingUnawarelatinIme_en_UK, switchingUnawarelatinIme_hi); |
| assertNextInputMethod(controller, true /* onlyCurrentIme */, |
| subtypeUnawareIme, null); |
| assertNextInputMethod(controller, true /* onlyCurrentIme */, |
| switchUnawareJapaneseIme_ja_JP, null); |
| } |
| } |