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 
17 package com.android.inputmethod.keyboard;
18 
19 import android.content.Context;
20 import android.content.res.Resources;
21 import android.test.AndroidTestCase;
22 import android.view.ContextThemeWrapper;
23 import android.view.inputmethod.EditorInfo;
24 import android.view.inputmethod.InputMethodInfo;
25 import android.view.inputmethod.InputMethodSubtype;
26 
27 import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils;
28 import com.android.inputmethod.keyboard.KeyboardLayoutSet.Builder;
29 import com.android.inputmethod.latin.R;
30 import com.android.inputmethod.latin.RichInputMethodManager;
31 import com.android.inputmethod.latin.RichInputMethodSubtype;
32 import com.android.inputmethod.latin.common.Constants;
33 import com.android.inputmethod.latin.settings.Settings;
34 import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils;
35 import com.android.inputmethod.latin.utils.ResourceUtils;
36 import com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
37 
38 import java.util.ArrayList;
39 import java.util.Locale;
40 
41 public 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 {
accept(final InputMethodSubtype subtype)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 
getKeyboardThemeForTests()67     protected abstract int getKeyboardThemeForTests();
68 
69     @Override
setUp()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
tearDown()100     protected void tearDown() throws Exception {
101         // Restore additional subtypes preference.
102         mRichImm.setAdditionalInputMethodSubtypes(mSavedAdditionalSubtypes);
103         super.tearDown();
104     }
105 
getAllSubtypesList()106     protected final ArrayList<InputMethodSubtype> getAllSubtypesList() {
107         return mAllSubtypesList;
108     }
109 
getSubtypesFilteredBy( final SubtypeFilter filter)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 
isPhone()121     protected final boolean isPhone() {
122         return Constants.isPhone(mScreenMetrics);
123     }
124 
getSubtype(final Locale locale, final String keyboardLayout)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 
createKeyboardLayoutSet(final InputMethodSubtype subtype, final EditorInfo editorInfo)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 
createKeyboardLayoutSet(final InputMethodSubtype subtype, final EditorInfo editorInfo, final boolean voiceInputKeyEnabled, final boolean languageSwitchKeyEnabled, final boolean splitLayoutEnabled)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