1/*
2 * Copyright (C) 2014 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
17package com.android.inputmethod.keyboard;
18
19import android.content.Context;
20import android.content.res.Resources;
21import android.test.AndroidTestCase;
22import android.view.ContextThemeWrapper;
23import android.view.inputmethod.EditorInfo;
24import android.view.inputmethod.InputMethodInfo;
25import android.view.inputmethod.InputMethodSubtype;
26
27import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils;
28import com.android.inputmethod.keyboard.KeyboardLayoutSet.Builder;
29import com.android.inputmethod.latin.R;
30import com.android.inputmethod.latin.RichInputMethodManager;
31import com.android.inputmethod.latin.RichInputMethodSubtype;
32import com.android.inputmethod.latin.common.Constants;
33import com.android.inputmethod.latin.settings.Settings;
34import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils;
35import com.android.inputmethod.latin.utils.ResourceUtils;
36import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
37
38import java.util.ArrayList;
39import java.util.Locale;
40
41public abstract class KeyboardLayoutSetTestsBase extends AndroidTestCase {
42    // All input method subtypes of LatinIME.
43    private final ArrayList<InputMethodSubtype> mAllSubtypesList = new ArrayList<>();
44
45    public interface SubtypeFilter {
46        public boolean accept(final InputMethodSubtype subtype);
47    }
48
49    public static final SubtypeFilter FILTER_IS_ASCII_CAPABLE = new SubtypeFilter() {
50        @Override
51        public boolean accept(InputMethodSubtype subtype) {
52            return InputMethodSubtypeCompatUtils.isAsciiCapable(subtype);
53        }
54    };
55
56    public static final SubtypeFilter FILTER_IS_ADDITIONAL_SUBTYPE = new SubtypeFilter() {
57        @Override
58        public boolean accept(InputMethodSubtype subtype) {
59            return AdditionalSubtypeUtils.isAdditionalSubtype(subtype);
60        }
61    };
62
63    private RichInputMethodManager mRichImm;
64    private InputMethodSubtype[] mSavedAdditionalSubtypes;
65    private int mScreenMetrics;
66
67    protected abstract int getKeyboardThemeForTests();
68
69    @Override
70    protected void setUp() throws Exception {
71        super.setUp();
72        final Context context = getContext();
73        final Resources res = context.getResources();
74        RichInputMethodManager.init(context);
75        mRichImm = RichInputMethodManager.getInstance();
76
77        // Save and reset additional subtypes preference.
78        mSavedAdditionalSubtypes = mRichImm.getAdditionalSubtypes();
79        final InputMethodSubtype[] predefinedAdditionalSubtypes =
80                AdditionalSubtypeUtils.createAdditionalSubtypesArray(
81                        AdditionalSubtypeUtils.createPrefSubtypes(
82                                res.getStringArray(R.array.predefined_subtypes)));
83        mRichImm.setAdditionalInputMethodSubtypes(predefinedAdditionalSubtypes);
84
85        final KeyboardTheme keyboardTheme = KeyboardTheme.searchKeyboardThemeById(
86                getKeyboardThemeForTests(), KeyboardTheme.KEYBOARD_THEMES);
87        setContext(new ContextThemeWrapper(getContext(), keyboardTheme.mStyleId));
88        KeyboardLayoutSet.onKeyboardThemeChanged();
89
90        mScreenMetrics = Settings.readScreenMetrics(res);
91
92        final InputMethodInfo imi = mRichImm.getInputMethodInfoOfThisIme();
93        final int subtypeCount = imi.getSubtypeCount();
94        for (int index = 0; index < subtypeCount; index++) {
95            mAllSubtypesList.add(imi.getSubtypeAt(index));
96        }
97    }
98
99    @Override
100    protected void tearDown() throws Exception {
101        // Restore additional subtypes preference.
102        mRichImm.setAdditionalInputMethodSubtypes(mSavedAdditionalSubtypes);
103        super.tearDown();
104    }
105
106    protected final ArrayList<InputMethodSubtype> getAllSubtypesList() {
107        return mAllSubtypesList;
108    }
109
110    protected final ArrayList<InputMethodSubtype> getSubtypesFilteredBy(
111            final SubtypeFilter filter) {
112        final ArrayList<InputMethodSubtype> list = new ArrayList<>();
113        for (final InputMethodSubtype subtype : mAllSubtypesList) {
114            if (filter.accept(subtype)) {
115                list.add(subtype);
116            }
117        }
118        return list;
119    }
120
121    protected final boolean isPhone() {
122        return Constants.isPhone(mScreenMetrics);
123    }
124
125    protected final InputMethodSubtype getSubtype(final Locale locale,
126            final String keyboardLayout) {
127        for (final InputMethodSubtype subtype : mAllSubtypesList) {
128            final Locale subtypeLocale = SubtypeLocaleUtils.getSubtypeLocale(subtype);
129            final String subtypeLayout = SubtypeLocaleUtils.getKeyboardLayoutSetName(subtype);
130            if (locale.equals(subtypeLocale) && keyboardLayout.equals(subtypeLayout)) {
131                // Found subtype that matches locale and keyboard layout.
132                return subtype;
133            }
134        }
135        for (final InputMethodSubtype subtype : getSubtypesFilteredBy(FILTER_IS_ASCII_CAPABLE)) {
136            final Locale subtypeLocale = SubtypeLocaleUtils.getSubtypeLocale(subtype);
137            if (locale.equals(subtypeLocale)) {
138                // Create additional subtype.
139                return AdditionalSubtypeUtils.createAsciiEmojiCapableAdditionalSubtype(
140                        locale.toString(), keyboardLayout);
141            }
142        }
143        throw new RuntimeException(
144                "Unknown subtype: locale=" + locale + " keyboardLayout=" + keyboardLayout);
145    }
146
147    protected KeyboardLayoutSet createKeyboardLayoutSet(final InputMethodSubtype subtype,
148            final EditorInfo editorInfo) {
149        return createKeyboardLayoutSet(subtype, editorInfo, false /* voiceInputKeyEnabled */,
150                false /* languageSwitchKeyEnabled */, false /* splitLayoutEnabled */);
151    }
152
153    protected KeyboardLayoutSet createKeyboardLayoutSet(final InputMethodSubtype subtype,
154            final EditorInfo editorInfo, final boolean voiceInputKeyEnabled,
155            final boolean languageSwitchKeyEnabled, final boolean splitLayoutEnabled) {
156        final Context context = getContext();
157        final Resources res = context.getResources();
158        final int keyboardWidth = ResourceUtils.getDefaultKeyboardWidth(res);
159        final int keyboardHeight = ResourceUtils.getDefaultKeyboardHeight(res);
160        final Builder builder = new Builder(context, editorInfo);
161        builder.setKeyboardGeometry(keyboardWidth, keyboardHeight)
162                .setSubtype(RichInputMethodSubtype.getRichInputMethodSubtype(subtype))
163                .setVoiceInputKeyEnabled(voiceInputKeyEnabled)
164                .setLanguageSwitchKeyEnabled(languageSwitchKeyEnabled)
165                .setSplitLayoutEnabledByUser(splitLayoutEnabled);
166        return builder.build();
167    }
168}
169