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