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.tv.settings.system; 18 19 import com.android.tv.settings.ActionBehavior; 20 import com.android.tv.settings.ActionKey; 21 import com.android.tv.settings.BaseSettingsActivity; 22 import com.android.tv.settings.R; 23 import com.android.tv.settings.dialog.old.Action; 24 import com.android.tv.settings.dialog.old.ActionAdapter; 25 26 import android.app.ActivityManagerNative; 27 import android.content.Intent; 28 import android.content.pm.PackageManager; 29 import android.os.Bundle; 30 import android.os.RemoteException; 31 import android.os.UserHandle; 32 import android.provider.Settings; 33 import android.text.TextUtils; 34 import android.util.Log; 35 import android.view.inputmethod.InputMethodInfo; 36 import android.view.inputmethod.InputMethodManager; 37 38 import java.util.ArrayList; 39 import java.util.Iterator; 40 import java.util.List; 41 42 public class KeyboardActivity extends BaseSettingsActivity implements ActionAdapter.Listener { 43 44 private static final String TAG = "KeyboardActivity"; 45 private static final boolean DEBUG = false; 46 47 private static final String INPUT_METHOD_SEPARATOR = ":"; 48 private InputMethodManager mInputMan; 49 50 @Override onCreate(Bundle savedInstanceState)51 public void onCreate(Bundle savedInstanceState) { 52 mInputMan = (InputMethodManager) getSystemService(INPUT_METHOD_SERVICE); 53 // enable all available input methods 54 enableAllInputMethods(); 55 56 super.onCreate(savedInstanceState); 57 } 58 59 @Override onActionClicked(Action action)60 public void onActionClicked(Action action) { 61 /* 62 * For list preferences 63 */ 64 String key = action.getKey(); 65 switch ((ActionType) mState) { 66 case KEYBOARD_OVERVIEW_CURRENT_KEYBOARD: 67 setInputMethod(key); 68 goBack(); 69 return; 70 default: 71 break; 72 } 73 74 /* 75 * For regular states 76 */ 77 ActionKey<ActionType, ActionBehavior> actionKey = new ActionKey<ActionType, ActionBehavior>( 78 ActionType.class, ActionBehavior.class, action.getKey()); 79 final ActionType type = actionKey.getType(); 80 switch (type) { 81 case KEYBOARD_OVERVIEW_CONFIGURE: 82 InputMethodInfo currentInputMethodInfo = getCurrentInputMethodInfo(); 83 if (currentInputMethodInfo != null && 84 currentInputMethodInfo.getSettingsActivity() != null) { 85 startActivity(getInputMethodSettingsIntent(currentInputMethodInfo)); 86 } 87 return; 88 default: 89 } 90 91 final ActionBehavior behavior = actionKey.getBehavior(); 92 if (behavior == null) { 93 return; 94 } 95 switch (behavior) { 96 case INIT: 97 setState(type, true); 98 break; 99 case ON: 100 setProperty(true); 101 break; 102 case OFF: 103 setProperty(false); 104 break; 105 default: 106 } 107 } 108 109 @Override getInitialState()110 protected Object getInitialState() { 111 return ActionType.KEYBOARD_OVERVIEW; 112 } 113 114 @Override refreshActionList()115 protected void refreshActionList() { 116 mActions.clear(); 117 InputMethodInfo currentInputMethodInfo = getCurrentInputMethodInfo(); 118 switch ((ActionType) mState) { 119 case KEYBOARD_OVERVIEW: 120 String name = getDefaultInputMethodName(); 121 mActions.add(ActionType.KEYBOARD_OVERVIEW_CURRENT_KEYBOARD 122 .toAction(mResources, TextUtils.isEmpty(name) ? "" : name)); 123 124 if (currentInputMethodInfo != null 125 && currentInputMethodInfo.getSettingsActivity() != null) { 126 mActions.add(ActionType.KEYBOARD_OVERVIEW_CONFIGURE.toAction(mResources)); 127 } 128 break; 129 case KEYBOARD_OVERVIEW_CURRENT_KEYBOARD: 130 mActions = Action.createActionsFromArrays(getInputMethodIds(), 131 getInputMethodNames()); 132 for (Action action : mActions) { 133 action.setChecked(currentInputMethodInfo != null && 134 action.getKey().equals(currentInputMethodInfo.getId())); 135 } 136 break; 137 default: 138 break; 139 } 140 } 141 142 @Override updateView()143 protected void updateView() { 144 refreshActionList(); 145 switch ((ActionType) mState) { 146 case KEYBOARD_OVERVIEW: 147 setView(R.string.system_keyboard, R.string.settings_app_name, 0, 148 R.drawable.ic_settings_keyboard); 149 break; 150 case KEYBOARD_OVERVIEW_CURRENT_KEYBOARD: 151 setView(R.string.title_current_keyboard, R.string.system_keyboard, 0, 152 R.drawable.ic_settings_keyboard); 153 break; 154 default: 155 break; 156 } 157 } 158 159 @Override setProperty(boolean enable)160 protected void setProperty(boolean enable) { 161 } 162 getDefaultInputMethodId()163 private String getDefaultInputMethodId() { 164 return Settings.Secure.getString(getContentResolver(), 165 Settings.Secure.DEFAULT_INPUT_METHOD); 166 } 167 getDefaultInputMethodName()168 private String getDefaultInputMethodName() { 169 String defaultInputMethodInfo = getDefaultInputMethodId(); 170 171 List<InputMethodInfo> enabledInputMethodInfos = getEnabledSystemInputMethodList(); 172 for (InputMethodInfo info : enabledInputMethodInfos) { 173 if (defaultInputMethodInfo.equals(info.getId())) { 174 return info.loadLabel(getPackageManager()).toString(); 175 } 176 } 177 return null; 178 } 179 getCurrentInputMethodInfo()180 private InputMethodInfo getCurrentInputMethodInfo() { 181 String defaultInputMethodInfo = getDefaultInputMethodId(); 182 183 List<InputMethodInfo> enabledInputMethodInfos = getEnabledSystemInputMethodList(); 184 for (InputMethodInfo info : enabledInputMethodInfos) { 185 if (defaultInputMethodInfo.equals(info.getId())) { 186 return info; 187 } 188 } 189 return null; 190 } 191 getInputMethodNames()192 private String[] getInputMethodNames() { 193 List<InputMethodInfo> enabledInputMethodInfos = getEnabledSystemInputMethodList(); 194 int totalInputMethods = enabledInputMethodInfos.size(); 195 String[] inputMethodNames = new String[totalInputMethods]; 196 for (int i = 0; i < totalInputMethods; i++) { 197 inputMethodNames[i] = enabledInputMethodInfos.get(i) 198 .loadLabel(getPackageManager()).toString(); 199 } 200 return inputMethodNames; 201 } 202 getInputMethodIds()203 private String[] getInputMethodIds() { 204 List<InputMethodInfo> enabledInputMethodInfos = getEnabledSystemInputMethodList(); 205 int totalInputMethods = enabledInputMethodInfos.size(); 206 String[] inputMethodIds = new String[totalInputMethods]; 207 for (int i = 0; i < totalInputMethods; i++) { 208 inputMethodIds[i] = enabledInputMethodInfos.get(i).getId(); 209 } 210 return inputMethodIds; 211 } 212 getEnabledSystemInputMethodList()213 private List<InputMethodInfo> getEnabledSystemInputMethodList() { 214 List<InputMethodInfo> enabledInputMethodInfos = 215 new ArrayList<>(mInputMan.getEnabledInputMethodList()); 216 // Filter auxiliary keyboards out 217 for (Iterator<InputMethodInfo> it = enabledInputMethodInfos.iterator(); it.hasNext();) { 218 if (it.next().isAuxiliaryIme()) { 219 it.remove(); 220 } 221 } 222 return enabledInputMethodInfos; 223 } 224 setInputMethod(String imid)225 private void setInputMethod(String imid) { 226 if (imid == null) { 227 throw new IllegalArgumentException("Unknown id: " + imid); 228 } 229 230 int userId; 231 try { 232 userId = ActivityManagerNative.getDefault().getCurrentUser().id; 233 Settings.Secure.putStringForUser(getContentResolver(), 234 Settings.Secure.DEFAULT_INPUT_METHOD, imid, userId); 235 236 if (ActivityManagerNative.isSystemReady()) { 237 Intent intent = new Intent(Intent.ACTION_INPUT_METHOD_CHANGED); 238 intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING); 239 intent.putExtra("input_method_id", imid); 240 sendBroadcastAsUser(intent, UserHandle.CURRENT); 241 } 242 } catch (RemoteException e) { 243 Log.d(TAG, "set default input method remote exception"); 244 } 245 } 246 enableAllInputMethods()247 private void enableAllInputMethods() { 248 List<InputMethodInfo> allInputMethodInfos = 249 new ArrayList<InputMethodInfo>(mInputMan.getInputMethodList()); 250 boolean needAppendSeparator = false; 251 StringBuilder builder = new StringBuilder(); 252 for (InputMethodInfo imi : allInputMethodInfos) { 253 if (needAppendSeparator) { 254 builder.append(INPUT_METHOD_SEPARATOR); 255 } else { 256 needAppendSeparator = true; 257 } 258 builder.append(imi.getId()); 259 } 260 Settings.Secure.putString(getContentResolver(), Settings.Secure.ENABLED_INPUT_METHODS, 261 builder.toString()); 262 } 263 getInputMethodSettingsIntent(InputMethodInfo imi)264 private Intent getInputMethodSettingsIntent(InputMethodInfo imi) { 265 final PackageManager pm = getPackageManager(); 266 final CharSequence label = imi.loadLabel(pm);// IME settings 267 final Intent intent; 268 final String settingsActivity = imi.getSettingsActivity(); 269 if (!TextUtils.isEmpty(settingsActivity)) { 270 intent = new Intent(Intent.ACTION_MAIN); 271 intent.setClassName(imi.getPackageName(), settingsActivity); 272 } else { 273 intent = null; 274 } 275 return intent; 276 } 277 } 278