• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019 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.car.settings.inputmethod;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 
21 import static org.mockito.Matchers.anyBoolean;
22 import static org.mockito.Matchers.eq;
23 import static org.mockito.Mockito.mock;
24 import static org.mockito.Mockito.when;
25 
26 import android.content.Context;
27 import android.content.pm.PackageManager;
28 import android.content.pm.PackageManager.NameNotFoundException;
29 import android.content.pm.ServiceInfo;
30 import android.graphics.drawable.Drawable;
31 import android.provider.Settings;
32 import android.view.inputmethod.InputMethodInfo;
33 import android.view.inputmethod.InputMethodManager;
34 import android.view.inputmethod.InputMethodSubtype;
35 import android.view.inputmethod.InputMethodSubtype.InputMethodSubtypeBuilder;
36 
37 import com.android.car.settings.CarSettingsRobolectricTestRunner;
38 
39 import org.junit.Before;
40 import org.junit.Test;
41 import org.junit.runner.RunWith;
42 import org.mockito.Mock;
43 import org.mockito.MockitoAnnotations;
44 import org.robolectric.RuntimeEnvironment;
45 
46 import java.util.ArrayList;
47 import java.util.Arrays;
48 import java.util.HashSet;
49 import java.util.List;
50 import java.util.Set;
51 import java.util.stream.Collectors;
52 
53 @RunWith(CarSettingsRobolectricTestRunner.class)
54 public class InputMethodUtilTest {
55     private static final String DUMMY_PACKAGE_NAME = "dummy package name";
56     private static final String DUMMY_LABEL = "dummy label";
57     private static final String DUMMY_SETTINGS_ACTIVITY = "dummy settings activity";
58     private static final String SUBTYPES_STRING =
59             "English (United States), German (Belgium), and Occitan (France)";
60     private static final String DUMMY_ENABLED_INPUT_METHODS =
61             "com.google.android.googlequicksearchbox/com.google.android.voicesearch.ime"
62                     + ".VoiceInputMethodService:com.google.android.apps.automotive.inputmethod/"
63                     + ".InputMethodService";
64     private static final String DUMMY_ENABLED_INPUT_METHOD_ID_DEFAULT =
65             "com.google.android.apps.automotive.inputmethod/.InputMethodService";
66     private static final String DUMMY_ENABLED_INPUT_METHOD_ID =
67             "com.google.android.googlequicksearchbox/com.google.android.voicesearch.ime"
68                     + ".VoiceInputMethodService";
69     private static final String DUMMY_DISABLED_INPUT_METHOD_ID = "disabled input method id";
70     private Context mContext;
71     private List<InputMethodInfo> mDummyEnabledInputMethodsListAllDefaultable;
72     private List<InputMethodInfo> mDummyEnabledInputMethodsListOneDefaultable;
73 
74     @Mock
75     private PackageManager mPackageManager;
76     @Mock
77     private InputMethodManager mInputMethodManager;
78     @Mock
79     private Drawable mIcon;
80 
81     @Before
setUp()82     public void setUp() {
83         MockitoAnnotations.initMocks(this);
84 
85         mContext = RuntimeEnvironment.application;
86 
87         Settings.Secure.putString(mContext.getContentResolver(),
88                 Settings.Secure.ENABLED_INPUT_METHODS, DUMMY_ENABLED_INPUT_METHODS);
89         Settings.Secure.putString(mContext.getContentResolver(),
90                 Settings.Secure.DEFAULT_INPUT_METHOD, DUMMY_ENABLED_INPUT_METHOD_ID_DEFAULT);
91 
92         mDummyEnabledInputMethodsListOneDefaultable = Arrays
93                 .stream(DUMMY_ENABLED_INPUT_METHODS.split(String.valueOf(InputMethodUtil
94                         .INPUT_METHOD_DELIMITER))).collect(Collectors.toList()).stream().map(
95                             result -> {
96                                 InputMethodInfo info = createMockInputMethodInfo(
97                                         mPackageManager, DUMMY_PACKAGE_NAME);
98                                 when(info.getId()).thenReturn(result);
99                                 when(info.isDefault(mContext)).thenReturn(result.equals(
100                                         DUMMY_ENABLED_INPUT_METHOD_ID_DEFAULT));
101                                 return info;
102                             }).collect(Collectors.toList());
103         mDummyEnabledInputMethodsListAllDefaultable = Arrays
104                 .stream(DUMMY_ENABLED_INPUT_METHODS.split(String.valueOf(InputMethodUtil
105                         .INPUT_METHOD_DELIMITER))).collect(Collectors.toList()).stream().map(
106                                 result -> {
107                                     InputMethodInfo info = createMockInputMethodInfo(
108                                             mPackageManager, DUMMY_PACKAGE_NAME);
109                                     when(info.getId()).thenReturn(result);
110                                     when(info.isDefault(mContext)).thenReturn(true);
111                                     return info;
112                                 }).collect(Collectors.toList());
113     }
114 
115     @Test
getPackageIcon_hasApplicationIcon()116     public void getPackageIcon_hasApplicationIcon() throws NameNotFoundException {
117         InputMethodInfo info = createMockInputMethodInfoWithSubtypes(mPackageManager,
118                 mInputMethodManager, DUMMY_PACKAGE_NAME);
119         when(mPackageManager.getApplicationIcon(eq(info.getPackageName()))).thenReturn(mIcon);
120         assertThat(InputMethodUtil.getPackageIcon(mPackageManager, info)).isEqualTo(mIcon);
121     }
122 
123     @Test
getPackageIcon_noApplicationIcon()124     public void getPackageIcon_noApplicationIcon() throws NameNotFoundException {
125         InputMethodInfo info = createMockInputMethodInfoWithSubtypes(mPackageManager,
126                 mInputMethodManager, DUMMY_PACKAGE_NAME);
127         when(mPackageManager.getApplicationIcon(DUMMY_PACKAGE_NAME)).thenThrow(
128                 new NameNotFoundException());
129         assertThat(InputMethodUtil.getPackageIcon(mPackageManager, info)).isEqualTo(
130                 InputMethodUtil.NO_ICON);
131     }
132 
133     @Test
getPackageLabel()134     public void getPackageLabel() {
135         InputMethodInfo info = createMockInputMethodInfoWithSubtypes(mPackageManager,
136                 mInputMethodManager, DUMMY_PACKAGE_NAME);
137         assertThat(InputMethodUtil.getPackageLabel(mPackageManager, info)).isEqualTo(
138                 DUMMY_LABEL);
139     }
140 
141     @Test
getSummaryString()142     public void getSummaryString() {
143         InputMethodInfo info = createMockInputMethodInfoWithSubtypes(mPackageManager,
144                 mInputMethodManager, DUMMY_PACKAGE_NAME);
145         assertThat(InputMethodUtil.getSummaryString(mContext, mInputMethodManager, info)).isEqualTo(
146                 SUBTYPES_STRING);
147     }
148 
149     @Test
isInputMethodEnabled_isDisabled_returnsFalse()150     public void isInputMethodEnabled_isDisabled_returnsFalse() {
151         InputMethodInfo info = createMockInputMethodInfo(mPackageManager, DUMMY_PACKAGE_NAME);
152         when(info.getId()).thenReturn(DUMMY_DISABLED_INPUT_METHOD_ID);
153 
154         assertThat(InputMethodUtil.isInputMethodEnabled(mContext.getContentResolver(), info))
155                 .isFalse();
156     }
157 
158     @Test
isInputMethodEnabled_isEnabled_returnsTrue()159     public void isInputMethodEnabled_isEnabled_returnsTrue() {
160         InputMethodInfo info = createMockInputMethodInfo(mPackageManager, DUMMY_PACKAGE_NAME);
161         when(info.getId()).thenReturn(DUMMY_ENABLED_INPUT_METHOD_ID_DEFAULT);
162 
163         assertThat(InputMethodUtil.isInputMethodEnabled(mContext.getContentResolver(), info))
164                 .isTrue();
165     }
166 
167     @Test
enableInputMethod_alreadyEnabled_remainsUnchanged()168     public void enableInputMethod_alreadyEnabled_remainsUnchanged() {
169         InputMethodInfo info = createMockInputMethodInfo(mPackageManager, DUMMY_PACKAGE_NAME);
170         when(info.getId()).thenReturn(DUMMY_ENABLED_INPUT_METHOD_ID_DEFAULT);
171 
172         InputMethodUtil.enableInputMethod(mContext.getContentResolver(), info);
173 
174         assertThat(Settings.Secure.getString(mContext.getContentResolver(),
175                 Settings.Secure.ENABLED_INPUT_METHODS)).isEqualTo(DUMMY_ENABLED_INPUT_METHODS);
176     }
177 
178     @Test
enableInputMethod_noEnabledInputMethods_addsIME()179     public void enableInputMethod_noEnabledInputMethods_addsIME() {
180         Settings.Secure.putString(mContext.getContentResolver(),
181                 Settings.Secure.ENABLED_INPUT_METHODS, "");
182         InputMethodInfo info = createMockInputMethodInfo(mPackageManager, DUMMY_PACKAGE_NAME);
183         when(info.getId()).thenReturn(DUMMY_ENABLED_INPUT_METHOD_ID_DEFAULT);
184 
185         InputMethodUtil.enableInputMethod(mContext.getContentResolver(), info);
186 
187         assertThat(Settings.Secure.getString(mContext.getContentResolver(),
188                 Settings.Secure.ENABLED_INPUT_METHODS)).isEqualTo(
189                 DUMMY_ENABLED_INPUT_METHOD_ID_DEFAULT);
190     }
191 
192     @Test
enableInputMethod_someEnabledInputMethods_addsIME()193     public void enableInputMethod_someEnabledInputMethods_addsIME() {
194         InputMethodInfo info = createMockInputMethodInfo(mPackageManager, DUMMY_PACKAGE_NAME);
195         when(info.getId()).thenReturn(DUMMY_DISABLED_INPUT_METHOD_ID);
196 
197         InputMethodUtil.enableInputMethod(mContext.getContentResolver(), info);
198 
199         assertThat(Settings.Secure.getString(mContext.getContentResolver(),
200                 Settings.Secure.ENABLED_INPUT_METHODS)).isEqualTo(
201                 DUMMY_ENABLED_INPUT_METHODS + ":"
202                         + DUMMY_DISABLED_INPUT_METHOD_ID);
203     }
204 
205     @Test
disableInputMethod_notEnabled_remainsUnchanged()206     public void disableInputMethod_notEnabled_remainsUnchanged() {
207         InputMethodInfo info = createMockInputMethodInfo(mPackageManager, DUMMY_PACKAGE_NAME);
208         when(info.getId()).thenReturn(DUMMY_DISABLED_INPUT_METHOD_ID);
209         when(mInputMethodManager.getEnabledInputMethodList())
210                 .thenReturn(mDummyEnabledInputMethodsListAllDefaultable);
211 
212         InputMethodUtil.disableInputMethod(mContext, mInputMethodManager, info);
213 
214         assertThat(Settings.Secure.getString(mContext.getContentResolver(),
215                 Settings.Secure.ENABLED_INPUT_METHODS)).isEqualTo(DUMMY_ENABLED_INPUT_METHODS);
216         assertThat(Settings.Secure.getString(mContext.getContentResolver(),
217                 Settings.Secure.DEFAULT_INPUT_METHOD)).isEqualTo(
218                 DUMMY_ENABLED_INPUT_METHOD_ID_DEFAULT);
219     }
220 
221     @Test
disableInputMethod_notDefault_removesIMEWhileDefaultRemainsSame()222     public void disableInputMethod_notDefault_removesIMEWhileDefaultRemainsSame() {
223         InputMethodInfo info = createMockInputMethodInfo(mPackageManager, DUMMY_PACKAGE_NAME);
224         when(info.getId()).thenReturn(DUMMY_ENABLED_INPUT_METHOD_ID);
225         when(mInputMethodManager.getEnabledInputMethodList())
226                 .thenReturn(mDummyEnabledInputMethodsListAllDefaultable);
227 
228         InputMethodUtil.disableInputMethod(mContext, mInputMethodManager, info);
229 
230         assertThat(splitConcatenatedIdsIntoSet(Settings.Secure.getString(mContext
231                 .getContentResolver(), Settings.Secure.ENABLED_INPUT_METHODS))).isEqualTo(
232                 splitConcatenatedIdsIntoSet(DUMMY_ENABLED_INPUT_METHOD_ID_DEFAULT));
233         assertThat(Settings.Secure.getString(mContext.getContentResolver(),
234                 Settings.Secure.DEFAULT_INPUT_METHOD)).isEqualTo(
235                 DUMMY_ENABLED_INPUT_METHOD_ID_DEFAULT);
236     }
237 
238     @Test
disableInputMethod_twoDefaultableIMEsEnabled_removesIMEAndChangesDefault()239     public void disableInputMethod_twoDefaultableIMEsEnabled_removesIMEAndChangesDefault() {
240         InputMethodInfo info = createMockInputMethodInfo(mPackageManager, DUMMY_PACKAGE_NAME);
241         when(info.getId()).thenReturn(DUMMY_ENABLED_INPUT_METHOD_ID_DEFAULT);
242         when(mInputMethodManager.getEnabledInputMethodList())
243                 .thenReturn(mDummyEnabledInputMethodsListAllDefaultable);
244 
245         InputMethodUtil.disableInputMethod(mContext, mInputMethodManager, info);
246 
247         assertThat(Settings.Secure.getString(mContext.getContentResolver(),
248                 Settings.Secure.ENABLED_INPUT_METHODS)).isEqualTo(
249                 DUMMY_ENABLED_INPUT_METHOD_ID);
250         assertThat(Settings.Secure.getString(mContext.getContentResolver(),
251                 Settings.Secure.DEFAULT_INPUT_METHOD)).isEqualTo(
252                 DUMMY_ENABLED_INPUT_METHOD_ID);
253     }
254 
255     @Test
disableInputMethod_isDefaultWithNoOtherDefaultableEnabled_remainsUnchanged()256     public void disableInputMethod_isDefaultWithNoOtherDefaultableEnabled_remainsUnchanged() {
257         InputMethodInfo info = createMockInputMethodInfo(mPackageManager, DUMMY_PACKAGE_NAME);
258         when(info.getId()).thenReturn(DUMMY_ENABLED_INPUT_METHOD_ID_DEFAULT);
259         when(mInputMethodManager.getEnabledInputMethodList())
260                 .thenReturn(mDummyEnabledInputMethodsListOneDefaultable);
261 
262         InputMethodUtil.disableInputMethod(mContext, mInputMethodManager, info);
263 
264         assertThat(splitConcatenatedIdsIntoSet(Settings.Secure.getString(mContext
265                 .getContentResolver(), Settings.Secure.ENABLED_INPUT_METHODS))).isEqualTo(
266                 splitConcatenatedIdsIntoSet(DUMMY_ENABLED_INPUT_METHODS));
267         assertThat(Settings.Secure.getString(mContext.getContentResolver(),
268                 Settings.Secure.DEFAULT_INPUT_METHOD)).isEqualTo(
269                 DUMMY_ENABLED_INPUT_METHOD_ID_DEFAULT);
270     }
271 
createMockInputMethodInfoWithSubtypes( PackageManager packageManager, InputMethodManager inputMethodManager, String packageName)272     private static InputMethodInfo createMockInputMethodInfoWithSubtypes(
273             PackageManager packageManager, InputMethodManager inputMethodManager,
274             String packageName) {
275         InputMethodInfo mockInfo = createMockInputMethodInfo(packageManager, packageName);
276         List<InputMethodSubtype> subtypes = createSubtypes();
277         when(inputMethodManager.getEnabledInputMethodSubtypeList(
278                 eq(mockInfo), anyBoolean())).thenReturn(subtypes);
279         return mockInfo;
280     }
281 
createMockInputMethodInfo( PackageManager packageManager, String packageName)282     private static InputMethodInfo createMockInputMethodInfo(
283             PackageManager packageManager, String packageName) {
284         InputMethodInfo mockInfo = mock(InputMethodInfo.class);
285         when(mockInfo.getPackageName()).thenReturn(packageName);
286         when(mockInfo.loadLabel(packageManager)).thenReturn(DUMMY_LABEL);
287         when(mockInfo.getServiceInfo()).thenReturn(new ServiceInfo());
288         when(mockInfo.getSettingsActivity()).thenReturn(DUMMY_SETTINGS_ACTIVITY);
289         return mockInfo;
290     }
291 
createSubtypes()292     private static List<InputMethodSubtype> createSubtypes() {
293         List<InputMethodSubtype> subtypes = new ArrayList<>();
294         subtypes.add(createSubtype(1, "en_US"));
295         subtypes.add(createSubtype(2, "de_BE"));
296         subtypes.add(createSubtype(3, "oc-FR"));
297         return subtypes;
298     }
299 
createSubtype(int id, String locale)300     private static InputMethodSubtype createSubtype(int id, String locale) {
301         return new InputMethodSubtypeBuilder().setSubtypeId(id).setSubtypeLocale(locale)
302                 .setIsAuxiliary(false).setIsAsciiCapable(true).build();
303     }
304 
splitConcatenatedIdsIntoSet(String ids)305     private Set<String> splitConcatenatedIdsIntoSet(String ids) {
306         Set<String> result = new HashSet<>();
307 
308         if (ids == null || ids.isEmpty()) {
309             return result;
310         }
311 
312         InputMethodUtil.sInputMethodSplitter.setString(ids);
313         while (InputMethodUtil.sInputMethodSplitter.hasNext()) {
314             result.add(InputMethodUtil.sInputMethodSplitter.next());
315         }
316 
317         return result;
318     }
319 }
320