Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d1da1152 authored by Yohei Yukawa's avatar Yohei Yukawa
Browse files

Add unit tests for InputMethodSubtypeSwitchingController

This CL adds unit tests for InputMethodSubtypeSwitchingController
as a ground work to make it aware of
supportsSwitchingToNextInputMethod in a subsequent CL.

This CL never changes existing behavior.

BUG: 12981505
Change-Id: I3b2c46c47c7686b811fa248ad549f20875367425
parent 64ab917e
Loading
Loading
Loading
Loading
+13 −2
Original line number Diff line number Diff line
@@ -259,7 +259,7 @@ public final class InputMethodInfo implements Parcelable {
    public InputMethodInfo(String packageName, String className,
            CharSequence label, String settingsActivity) {
        this(buildDummyResolveInfo(packageName, className, label), false, settingsActivity, null,
                0, false);
                0, false /* forceDefault */, true /* supportsSwitchingToNextInputMethod */);
    }

    /**
@@ -269,6 +269,17 @@ public final class InputMethodInfo implements Parcelable {
    public InputMethodInfo(ResolveInfo ri, boolean isAuxIme,
            String settingsActivity, List<InputMethodSubtype> subtypes, int isDefaultResId,
            boolean forceDefault) {
        this(ri, isAuxIme, settingsActivity, subtypes, isDefaultResId,
                forceDefault, true /* supportsSwitchingToNextInputMethod */);
    }

    /**
     * Temporary API for creating a built-in input method for test.
     * @hide
     */
    public InputMethodInfo(ResolveInfo ri, boolean isAuxIme,
            String settingsActivity, List<InputMethodSubtype> subtypes, int isDefaultResId,
            boolean forceDefault, boolean supportsSwitchingToNextInputMethod) {
        final ServiceInfo si = ri.serviceInfo;
        mService = ri;
        mId = new ComponentName(si.packageName, si.name).flattenToShortString();
@@ -277,7 +288,7 @@ public final class InputMethodInfo implements Parcelable {
        mIsAuxIme = isAuxIme;
        mSubtypes = new InputMethodSubtypeArray(subtypes);
        mForceDefault = forceDefault;
        mSupportsSwitchingToNextInputMethod = true;
        mSupportsSwitchingToNextInputMethod = supportsSwitchingToNextInputMethod;
    }

    private static ResolveInfo buildDummyResolveInfo(String packageName, String className,
+38 −37
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.internal.inputmethod;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.inputmethod.InputMethodUtils.InputMethodSettings;

import android.content.Context;
@@ -119,14 +120,14 @@ public class InputMethodSubtypeSwitchingController {
        }
    }

    private static class InputMethodAndSubtypeCircularList {
    private static class InputMethodAndSubtypeList {
        private final Context mContext;
        // Used to load label
        private final PackageManager mPm;
        private final String mSystemLocaleStr;
        private final InputMethodSettings mSettings;

        public InputMethodAndSubtypeCircularList(Context context, InputMethodSettings settings) {
        public InputMethodAndSubtypeList(Context context, InputMethodSettings settings) {
            mContext = context;
            mSettings = settings;
            mPm = context.getPackageManager();
@@ -152,38 +153,6 @@ public class InputMethodSubtypeSwitchingController {
                            }
                        });

        public ImeSubtypeListItem getNextInputMethod(
                boolean onlyCurrentIme, InputMethodInfo imi, InputMethodSubtype subtype) {
            if (imi == null) {
                return null;
            }
            final List<ImeSubtypeListItem> imList =
                    getSortedInputMethodAndSubtypeList();
            if (imList.size() <= 1) {
                return null;
            }
            final int N = imList.size();
            final int currentSubtypeId =
                    subtype != null ? InputMethodUtils.getSubtypeIdFromHashCode(imi,
                            subtype.hashCode()) : NOT_A_SUBTYPE_ID;
            for (int i = 0; i < N; ++i) {
                final ImeSubtypeListItem isli = imList.get(i);
                if (isli.mImi.equals(imi) && isli.mSubtypeId == currentSubtypeId) {
                    if (!onlyCurrentIme) {
                        return imList.get((i + 1) % N);
                    }
                    for (int j = 0; j < N - 1; ++j) {
                        final ImeSubtypeListItem candidate = imList.get((i + j + 1) % N);
                        if (candidate.mImi.equals(imi)) {
                            return candidate;
                        }
                    }
                    return null;
                }
            }
            return null;
        }

        public List<ImeSubtypeListItem> getSortedInputMethodAndSubtypeList() {
            return getSortedInputMethodAndSubtypeList(true, false, false);
        }
@@ -247,7 +216,38 @@ public class InputMethodSubtypeSwitchingController {
    private final ArrayDeque<SubtypeParams> mTypedSubtypeHistory = new ArrayDeque<SubtypeParams>();
    private final Object mLock = new Object();
    private final InputMethodSettings mSettings;
    private InputMethodAndSubtypeCircularList mSubtypeList;
    private InputMethodAndSubtypeList mSubtypeList;

    @VisibleForTesting
    public static ImeSubtypeListItem getNextInputMethodImpl(List<ImeSubtypeListItem> imList,
            boolean onlyCurrentIme, InputMethodInfo imi, InputMethodSubtype subtype) {
        if (imi == null) {
            return null;
        }
        if (imList.size() <= 1) {
            return null;
        }
        final int N = imList.size();
        final int currentSubtypeId =
                subtype != null ? InputMethodUtils.getSubtypeIdFromHashCode(imi,
                        subtype.hashCode()) : NOT_A_SUBTYPE_ID;
        for (int i = 0; i < N; ++i) {
            final ImeSubtypeListItem isli = imList.get(i);
            if (isli.mImi.equals(imi) && isli.mSubtypeId == currentSubtypeId) {
                if (!onlyCurrentIme) {
                    return imList.get((i + 1) % N);
                }
                for (int j = 0; j < N - 1; ++j) {
                    final ImeSubtypeListItem candidate = imList.get((i + j + 1) % N);
                    if (candidate.mImi.equals(imi)) {
                        return candidate;
                    }
                }
                return null;
            }
        }
        return null;
    }

    public InputMethodSubtypeSwitchingController(InputMethodSettings settings) {
        mSettings = settings;
@@ -278,14 +278,15 @@ public class InputMethodSubtypeSwitchingController {

    public void resetCircularListLocked(Context context) {
        synchronized(mLock) {
            mSubtypeList = new InputMethodAndSubtypeCircularList(context, mSettings);
            mSubtypeList = new InputMethodAndSubtypeList(context, mSettings);
        }
    }

    public ImeSubtypeListItem getNextInputMethod(
            boolean onlyCurrentIme, InputMethodInfo imi, InputMethodSubtype subtype) {
        synchronized(mLock) {
            return mSubtypeList.getNextInputMethod(onlyCurrentIme, imi, subtype);
            return getNextInputMethodImpl(mSubtypeList.getSortedInputMethodAndSubtypeList(),
                    onlyCurrentIme, imi, subtype);
        }
    }

+1 −1
Original line number Diff line number Diff line
@@ -21,4 +21,4 @@ if [[ $rebuild == true ]]; then
  $COMMAND
fi

adb shell am instrument -w -e class android.os.InputMethodTest,android.os.InputMethodSubtypeArrayTest com.android.frameworks.coretests.inputmethod/android.test.InstrumentationTestRunner
adb shell am instrument -w -e class android.os.InputMethodTest,android.os.InputMethodSubtypeArrayTest,android.os.InputMethodSubtypeSwitchingControllerTest com.android.frameworks.coretests.inputmethod/android.test.InstrumentationTestRunner
+205 −0
Original line number Diff line number Diff line
/*
 * 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;
import com.android.internal.inputmethod.InputMethodSubtypeSwitchingController.ImeSubtypeListItem;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class InputMethodSubtypeSwitchingControllerTest extends InstrumentationTestCase {
    final private static String DUMMY_PACKAGE_NAME = "dymmy package name";
    final private static String DUMMY_SETTING_ACTIVITY_NAME = "";
    final private static boolean DUMMY_IS_AUX_IME = false;
    final private static boolean DUMMY_FORCE_DEFAULT = false;
    final private static int DUMMY_IS_DEFAULT_RES_ID = 0;
    final private static String SYSTEM_LOCALE = "en_US";

    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;
        final List<InputMethodSubtype> 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);
        for (int i = 0; i < subtypes.size(); ++i) {
            final String subtypeLocale = subtypeLocales.get(i);
            final InputMethodSubtype subtype = subtypes.get(i);
            items.add(new ImeSubtypeListItem(imeName, subtypeLocale, imi, i, subtypeLocale,
                    SYSTEM_LOCALE));
        }
    }

    private static List<ImeSubtypeListItem> createTestData() {
        final List<ImeSubtypeListItem> items = new ArrayList<ImeSubtypeListItem>();
        addDummyImeSubtypeListItems(items, "switchAwareLatinIme", "switchAwareLatinIme",
                Arrays.asList("en_US", "es_US", "fr"),
                true /* supportsSwitchingToNextInputMethod*/);
        addDummyImeSubtypeListItems(items, "nonSwitchAwareLatinIme", "nonSwitchAwareLatinIme",
                Arrays.asList("en_UK", "hi"),
                false /* supportsSwitchingToNextInputMethod*/);
        addDummyImeSubtypeListItems(items, "switchAwareJapaneseIme", "switchAwareJapaneseIme",
                Arrays.asList("ja_JP"),
                true /* supportsSwitchingToNextInputMethod*/);
        addDummyImeSubtypeListItems(items, "nonSwitchAwareJapaneseIme", "nonSwitchAwareJapaneseIme",
                Arrays.asList("ja_JP"),
                false /* supportsSwitchingToNextInputMethod*/);
        return items;
    }

    @SmallTest
    public void testGetNextInputMethodImplWithNotOnlyCurrentIme() throws Exception {
        final List<ImeSubtypeListItem> imList = createTestData();

        final boolean ONLY_CURRENT_IME = false;
        ImeSubtypeListItem currentIme;
        ImeSubtypeListItem nextIme;

        // "switchAwareLatinIme/en_US" -> "switchAwareLatinIme/es_US"
        currentIme = imList.get(0);
        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
                        currentIme.mSubtypeName.toString()));
        assertEquals(imList.get(1), nextIme);
        // "switchAwareLatinIme/es_US" -> "switchAwareLatinIme/fr"
        currentIme = imList.get(1);
        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
                        currentIme.mSubtypeName.toString()));
        assertEquals(imList.get(2), nextIme);
        // "switchAwareLatinIme/fr" -> "nonSwitchAwareLatinIme/en_UK
        currentIme = imList.get(2);
        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
                        currentIme.mSubtypeName.toString()));
        assertEquals(imList.get(3), nextIme);
        // "nonSwitchAwareLatinIme/en_UK" -> "nonSwitchAwareLatinIme/hi"
        currentIme = imList.get(3);
        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
                        currentIme.mSubtypeName.toString()));
        assertEquals(imList.get(4), nextIme);
        // "nonSwitchAwareLatinIme/hi" -> "switchAwareJapaneseIme/ja_JP"
        currentIme = imList.get(4);
        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
                        currentIme.mSubtypeName.toString()));
        assertEquals(imList.get(5), nextIme);
        // "switchAwareJapaneseIme/ja_JP" -> "nonSwitchAwareJapaneseIme/ja_JP"
        currentIme = imList.get(5);
        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
                        currentIme.mSubtypeName.toString()));
        assertEquals(imList.get(6), nextIme);
        // "nonSwitchAwareJapaneseIme/ja_JP" -> "switchAwareLatinIme/en_US"
        currentIme = imList.get(6);
        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
                        currentIme.mSubtypeName.toString()));
        assertEquals(imList.get(0), nextIme);
    }

    @SmallTest
    public void testGetNextInputMethodImplWithOnlyCurrentIme() throws Exception {
        final List<ImeSubtypeListItem> imList = createTestData();

        final boolean ONLY_CURRENT_IME = true;
        ImeSubtypeListItem currentIme;
        ImeSubtypeListItem nextIme;

        // "switchAwareLatinIme/en_US" -> "switchAwareLatinIme/es_US"
        currentIme = imList.get(0);
        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
                        currentIme.mSubtypeName.toString()));
        assertEquals(imList.get(1), nextIme);
        // "switchAwareLatinIme/es_US" -> "switchAwareLatinIme/fr"
        currentIme = imList.get(1);
        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
                        currentIme.mSubtypeName.toString()));
        assertEquals(imList.get(2), nextIme);
        // "switchAwareLatinIme/fr" -> "switchAwareLatinIme/en_US"
        currentIme = imList.get(2);
        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
                        currentIme.mSubtypeName.toString()));
        assertEquals(imList.get(0), nextIme);

        // "nonSwitchAwareLatinIme/en_UK" -> "nonSwitchAwareLatinIme/hi"
        currentIme = imList.get(3);
        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
                        currentIme.mSubtypeName.toString()));
        assertEquals(imList.get(4), nextIme);
        // "nonSwitchAwareLatinIme/hi" -> "switchAwareLatinIme/en_UK"
        currentIme = imList.get(4);
        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
                        currentIme.mSubtypeName.toString()));
        assertEquals(imList.get(3), nextIme);

        // "switchAwareJapaneseIme/ja_JP" -> null
        currentIme = imList.get(5);
        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
                        currentIme.mSubtypeName.toString()));
        assertNull(nextIme);

        // "nonSwitchAwareJapaneseIme/ja_JP" -> null
        currentIme = imList.get(6);
        nextIme = InputMethodSubtypeSwitchingController.getNextInputMethodImpl(
                imList, ONLY_CURRENT_IME, currentIme.mImi, createDummySubtype(
                        currentIme.mSubtypeName.toString()));
        assertNull(nextIme);
    }
 }