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.testutils; 18 19 import android.provider.Settings; 20 import android.view.inputmethod.InputMethodInfo; 21 import android.view.inputmethod.InputMethodManager; 22 import android.view.inputmethod.InputMethodSubtype; 23 24 import androidx.annotation.Nullable; 25 26 import com.android.car.settings.inputmethod.InputMethodUtil; 27 28 import org.robolectric.RuntimeEnvironment; 29 import org.robolectric.annotation.Implementation; 30 import org.robolectric.annotation.Implements; 31 import org.robolectric.annotation.Resetter; 32 33 import java.util.ArrayList; 34 import java.util.HashMap; 35 import java.util.List; 36 import java.util.Map; 37 import java.util.stream.Collectors; 38 39 @Implements(value = InputMethodManager.class) 40 public class ShadowInputMethodManager extends org.robolectric.shadows.ShadowInputMethodManager { 41 private static List<InputMethodSubtype> sInputMethodSubtypes = new ArrayList<>(); 42 private static List<InputMethodInfo> sInputMethodList = new ArrayList<>(); 43 private static Map<String, InputMethodInfo> sInputMethodMap = new HashMap<>(); 44 45 @Resetter reset()46 public static void reset() { 47 sInputMethodSubtypes.clear(); 48 sInputMethodList.clear(); 49 sInputMethodMap.clear(); 50 org.robolectric.shadows.ShadowInputMethodManager.reset(); 51 } 52 setEnabledInputMethodSubtypeList(List<InputMethodSubtype> list)53 public static void setEnabledInputMethodSubtypeList(List<InputMethodSubtype> list) { 54 sInputMethodSubtypes = list; 55 } 56 57 @Implementation getEnabledInputMethodSubtypeList(InputMethodInfo imi, boolean allowsImplicitlySelectedSubtypes)58 protected List<InputMethodSubtype> getEnabledInputMethodSubtypeList(InputMethodInfo imi, 59 boolean allowsImplicitlySelectedSubtypes) { 60 return sInputMethodSubtypes; 61 } 62 setEnabledInputMethodList(@ullable List<InputMethodInfo> list)63 public static void setEnabledInputMethodList(@Nullable List<InputMethodInfo> list) { 64 if (list == null || list.size() == 0) { 65 Settings.Secure.putString(RuntimeEnvironment.application.getContentResolver(), 66 Settings.Secure.ENABLED_INPUT_METHODS, ""); 67 return; 68 } 69 70 String concatenatedInputMethodIds = createInputMethodIdString(list.stream().map( 71 imi -> imi.getId()).collect(Collectors.toList()).toArray(new String[list.size()])); 72 Settings.Secure.putString(RuntimeEnvironment.application.getContentResolver(), 73 Settings.Secure.ENABLED_INPUT_METHODS, concatenatedInputMethodIds); 74 addInputMethodInfosToMap(list); 75 } 76 77 @Implementation getEnabledInputMethodList()78 protected List<InputMethodInfo> getEnabledInputMethodList() { 79 List<InputMethodInfo> enabledInputMethodList = new ArrayList<>(); 80 81 String inputMethodIdString = Settings.Secure.getString( 82 RuntimeEnvironment.application.getContentResolver(), 83 Settings.Secure.ENABLED_INPUT_METHODS); 84 if (inputMethodIdString == null || inputMethodIdString.isEmpty()) { 85 return enabledInputMethodList; 86 } 87 88 InputMethodUtil.sInputMethodSplitter.setString(inputMethodIdString); 89 while (InputMethodUtil.sInputMethodSplitter.hasNext()) { 90 enabledInputMethodList.add(sInputMethodMap.get(InputMethodUtil.sInputMethodSplitter 91 .next())); 92 } 93 return enabledInputMethodList; 94 } 95 setInputMethodList(List<InputMethodInfo> inputMethodInfos)96 public void setInputMethodList(List<InputMethodInfo> inputMethodInfos) { 97 sInputMethodList = inputMethodInfos; 98 if (inputMethodInfos == null) { 99 return; 100 } 101 102 addInputMethodInfosToMap(inputMethodInfos); 103 } 104 105 @Implementation getInputMethodList()106 protected List<InputMethodInfo> getInputMethodList() { 107 return sInputMethodList; 108 } 109 createInputMethodIdString(String... ids)110 private static String createInputMethodIdString(String... ids) { 111 int size = ids == null ? 0 : ids.length; 112 113 if (size == 1) { 114 return ids[0]; 115 } 116 117 StringBuilder builder = new StringBuilder(); 118 for (int i = 0; i < size; i++) { 119 builder.append(ids[i]); 120 if (i != size - 1) { 121 builder.append(InputMethodUtil.INPUT_METHOD_DELIMITER); 122 } 123 } 124 return builder.toString(); 125 } 126 addInputMethodInfosToMap(List<InputMethodInfo> inputMethodInfos)127 private static void addInputMethodInfosToMap(List<InputMethodInfo> inputMethodInfos) { 128 if (sInputMethodMap == null || sInputMethodMap.size() == 0) { 129 sInputMethodMap = inputMethodInfos.stream().collect(Collectors.toMap( 130 InputMethodInfo::getId, imi -> imi)); 131 return; 132 } 133 134 inputMethodInfos.forEach(imi -> { 135 sInputMethodMap.put(imi.getId(), imi); 136 }); 137 } 138 } 139