Home | History | Annotate | Download | only in inputmethod
      1 /*
      2  * Copyright (C) 2017 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.inputmethod;
     18 
     19 import android.app.ActivityManager;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.content.pm.PackageManager;
     23 import android.os.Bundle;
     24 import android.os.RemoteException;
     25 import android.os.UserHandle;
     26 import android.provider.Settings;
     27 import android.support.v17.preference.LeanbackPreferenceFragment;
     28 import android.support.v7.preference.ListPreference;
     29 import android.support.v7.preference.Preference;
     30 import android.support.v7.preference.PreferenceScreen;
     31 import android.text.TextUtils;
     32 import android.util.ArraySet;
     33 import android.util.Log;
     34 import android.view.inputmethod.InputMethodInfo;
     35 import android.view.inputmethod.InputMethodManager;
     36 
     37 import com.android.tv.settings.R;
     38 
     39 import java.util.ArrayList;
     40 import java.util.List;
     41 import java.util.Set;
     42 
     43 /**
     44  * Fragment for managing IMEs
     45  */
     46 public class KeyboardFragment extends LeanbackPreferenceFragment {
     47     private static final String TAG = "KeyboardFragment";
     48     private static final String KEY_CURRENT_KEYBOARD = "currentKeyboard";
     49     private static final String KEY_MANAGE_KEYBOARDS = "manageKeyboards";
     50 
     51     private static final String KEY_KEYBOARD_SETTINGS_PREFIX = "keyboardSettings:";
     52 
     53     private InputMethodManager mInputMethodManager;
     54 
     55     /**
     56      * @return New fragment instance
     57      */
     58     public static KeyboardFragment newInstance() {
     59         return new KeyboardFragment();
     60     }
     61 
     62     @Override
     63     public void onCreate(Bundle savedInstanceState) {
     64         mInputMethodManager =
     65                 (InputMethodManager) getActivity().getSystemService(Context.INPUT_METHOD_SERVICE);
     66 
     67         super.onCreate(savedInstanceState);
     68     }
     69 
     70     @Override
     71     public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
     72         final Context preferenceContext = getPreferenceManager().getContext();
     73 
     74         final PreferenceScreen screen =
     75                 getPreferenceManager().createPreferenceScreen(preferenceContext);
     76         screen.setTitle(R.string.system_keyboard);
     77         setPreferenceScreen(screen);
     78 
     79         final ListPreference currentKeyboard = new ListPreference(preferenceContext);
     80         currentKeyboard.setPersistent(false);
     81         currentKeyboard.setTitle(R.string.title_current_keyboard);
     82         currentKeyboard.setDialogTitle(R.string.title_current_keyboard);
     83         currentKeyboard.setSummary("%s");
     84         currentKeyboard.setKey(KEY_CURRENT_KEYBOARD);
     85         currentKeyboard.setOnPreferenceChangeListener((preference, newValue) -> {
     86             setInputMethod((String) newValue);
     87             return true;
     88         });
     89         updateCurrentKeyboardPreference(currentKeyboard);
     90         screen.addPreference(currentKeyboard);
     91 
     92         final Preference manageKeyboards = new Preference(preferenceContext);
     93         manageKeyboards.setTitle(R.string.manage_keyboards);
     94         manageKeyboards.setKey(KEY_MANAGE_KEYBOARDS);
     95         manageKeyboards.setFragment(AvailableVirtualKeyboardFragment.class.getName());
     96         screen.addPreference(manageKeyboards);
     97 
     98         updatePrefs();
     99     }
    100 
    101     @Override
    102     public void onResume() {
    103         super.onResume();
    104         updatePrefs();
    105         final Preference currentKeyboard = findPreference(KEY_CURRENT_KEYBOARD);
    106         if (currentKeyboard instanceof ListPreference) {
    107             updateCurrentKeyboardPreference((ListPreference) currentKeyboard);
    108         }
    109     }
    110 
    111     private void updateCurrentKeyboardPreference(ListPreference currentKeyboardPref) {
    112         final PackageManager packageManager = getActivity().getPackageManager();
    113         List<InputMethodInfo> enabledInputMethodInfos = getEnabledSystemInputMethodList();
    114         final List<CharSequence> entries = new ArrayList<>(enabledInputMethodInfos.size());
    115         final List<CharSequence> values = new ArrayList<>(enabledInputMethodInfos.size());
    116 
    117         int defaultIndex = 0;
    118         final String defaultId = Settings.Secure.getString(getActivity().getContentResolver(),
    119                 Settings.Secure.DEFAULT_INPUT_METHOD);
    120 
    121         for (final InputMethodInfo info : enabledInputMethodInfos) {
    122             entries.add(info.loadLabel(packageManager));
    123             final String id = info.getId();
    124             values.add(id);
    125             if (TextUtils.equals(id, defaultId)) {
    126                 defaultIndex = values.size() - 1;
    127             }
    128         }
    129 
    130         currentKeyboardPref.setEntries(entries.toArray(new CharSequence[entries.size()]));
    131         currentKeyboardPref.setEntryValues(values.toArray(new CharSequence[values.size()]));
    132         if (entries.size() > 0) {
    133             currentKeyboardPref.setValueIndex(defaultIndex);
    134         }
    135     }
    136 
    137     private void updatePrefs() {
    138         final Context preferenceContext = getPreferenceManager().getContext();
    139         final PackageManager packageManager = getActivity().getPackageManager();
    140         List<InputMethodInfo> enabledInputMethodInfos = getEnabledSystemInputMethodList();
    141 
    142         final PreferenceScreen screen = getPreferenceScreen();
    143 
    144         final Set<String> enabledInputMethodKeys = new ArraySet<>(enabledInputMethodInfos.size());
    145         // Add per-IME settings
    146         for (final InputMethodInfo info : enabledInputMethodInfos) {
    147             final Intent settingsIntent = getInputMethodSettingsIntent(info);
    148             if (settingsIntent == null) {
    149                 continue;
    150             }
    151             final String key = KEY_KEYBOARD_SETTINGS_PREFIX + info.getId();
    152 
    153             Preference preference = findPreference(key);
    154             if (preference == null) {
    155                 preference = new Preference(preferenceContext);
    156                 screen.addPreference(preference);
    157             }
    158             preference.setTitle(info.loadLabel(packageManager));
    159             preference.setKey(key);
    160             preference.setIntent(settingsIntent);
    161             enabledInputMethodKeys.add(key);
    162         }
    163 
    164         for (int i = 0; i < screen.getPreferenceCount();) {
    165             final Preference preference = screen.getPreference(i);
    166             final String key = preference.getKey();
    167             if (!TextUtils.isEmpty(key)
    168                     && key.startsWith(KEY_KEYBOARD_SETTINGS_PREFIX)
    169                     && !enabledInputMethodKeys.contains(key)) {
    170                 screen.removePreference(preference);
    171             } else {
    172                 i++;
    173             }
    174         }
    175     }
    176 
    177     private void setInputMethod(String imid) {
    178         if (imid == null) {
    179             throw new IllegalArgumentException("Null ID");
    180         }
    181 
    182         int userId;
    183         try {
    184             userId = ActivityManager.getService().getCurrentUser().id;
    185             Settings.Secure.putStringForUser(getActivity().getContentResolver(),
    186                     Settings.Secure.DEFAULT_INPUT_METHOD, imid, userId);
    187 
    188             Intent intent = new Intent(Intent.ACTION_INPUT_METHOD_CHANGED);
    189             intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
    190             intent.putExtra("input_method_id", imid);
    191             getActivity().sendBroadcastAsUser(intent, UserHandle.CURRENT);
    192         } catch (RemoteException e) {
    193             Log.d(TAG, "set default input method remote exception");
    194         }
    195     }
    196 
    197     private List<InputMethodInfo> getEnabledSystemInputMethodList() {
    198         List<InputMethodInfo> enabledInputMethodInfos =
    199                 new ArrayList<>(mInputMethodManager.getEnabledInputMethodList());
    200         // Filter auxiliary keyboards out
    201         enabledInputMethodInfos.removeIf(InputMethodInfo::isAuxiliaryIme);
    202         return enabledInputMethodInfos;
    203     }
    204 
    205     private Intent getInputMethodSettingsIntent(InputMethodInfo imi) {
    206         final Intent intent;
    207         final String settingsActivity = imi.getSettingsActivity();
    208         if (!TextUtils.isEmpty(settingsActivity)) {
    209             intent = new Intent(Intent.ACTION_MAIN);
    210             intent.setClassName(imi.getPackageName(), settingsActivity);
    211         } else {
    212             intent = null;
    213         }
    214         return intent;
    215     }
    216 }
    217