14a5f889f80b683446e498f244d0eadfd979ca5d0satok/*
24a5f889f80b683446e498f244d0eadfd979ca5d0satok * Copyright (C) 2010 The Android Open Source Project
34a5f889f80b683446e498f244d0eadfd979ca5d0satok *
44a5f889f80b683446e498f244d0eadfd979ca5d0satok * Licensed under the Apache License, Version 2.0 (the "License");
54a5f889f80b683446e498f244d0eadfd979ca5d0satok * you may not use this file except in compliance with the License.
64a5f889f80b683446e498f244d0eadfd979ca5d0satok * You may obtain a copy of the License at
74a5f889f80b683446e498f244d0eadfd979ca5d0satok *
84a5f889f80b683446e498f244d0eadfd979ca5d0satok *      http://www.apache.org/licenses/LICENSE-2.0
94a5f889f80b683446e498f244d0eadfd979ca5d0satok *
104a5f889f80b683446e498f244d0eadfd979ca5d0satok * Unless required by applicable law or agreed to in writing, software
114a5f889f80b683446e498f244d0eadfd979ca5d0satok * distributed under the License is distributed on an "AS IS" BASIS,
124a5f889f80b683446e498f244d0eadfd979ca5d0satok * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134a5f889f80b683446e498f244d0eadfd979ca5d0satok * See the License for the specific language governing permissions and
144a5f889f80b683446e498f244d0eadfd979ca5d0satok * limitations under the License.
154a5f889f80b683446e498f244d0eadfd979ca5d0satok */
164a5f889f80b683446e498f244d0eadfd979ca5d0satok
170417e4094713c5f4dac700b645000d0959bf62fasatokpackage com.android.settings.inputmethod;
180417e4094713c5f4dac700b645000d0959bf62fasatok
194a5f889f80b683446e498f244d0eadfd979ca5d0satokimport android.content.Context;
205e9c5e7bcfbdc3d61f80bc95d16a7d57a362bc39satokimport android.content.Intent;
214a5f889f80b683446e498f244d0eadfd979ca5d0satokimport android.content.pm.PackageManager;
224a5f889f80b683446e498f244d0eadfd979ca5d0satokimport android.content.res.Configuration;
234a5f889f80b683446e498f244d0eadfd979ca5d0satokimport android.os.Bundle;
244a5f889f80b683446e498f244d0eadfd979ca5d0satokimport android.preference.Preference;
255d56f6217f237ec6f1dc20a1c9f7886ca3c6a717Tadashi G. Takaokaimport android.preference.Preference.OnPreferenceChangeListener;
264a5f889f80b683446e498f244d0eadfd979ca5d0satokimport android.preference.PreferenceCategory;
274a5f889f80b683446e498f244d0eadfd979ca5d0satokimport android.preference.PreferenceScreen;
281f53937469095f268d4c7a21d93f821a341a151dTadashi G. Takaokaimport android.preference.TwoStatePreference;
29c88a7ff1efd10374974e45768bde1658cc1d8483satokimport android.text.TextUtils;
304a5f889f80b683446e498f244d0eadfd979ca5d0satokimport android.view.inputmethod.InputMethodInfo;
314a5f889f80b683446e498f244d0eadfd979ca5d0satokimport android.view.inputmethod.InputMethodManager;
324a5f889f80b683446e498f244d0eadfd979ca5d0satokimport android.view.inputmethod.InputMethodSubtype;
334a5f889f80b683446e498f244d0eadfd979ca5d0satok
3455aee124063dc28e740efcfdadafa5738b0b538aTadashi G. Takaokaimport com.android.settings.R;
3555aee124063dc28e740efcfdadafa5738b0b538aTadashi G. Takaokaimport com.android.settings.SettingsPreferenceFragment;
3655aee124063dc28e740efcfdadafa5738b0b538aTadashi G. Takaoka
37ef120bea7b8cb3b891ae3f39d7a97989c107a16fSatoshi Kataokaimport java.text.Collator;
384a5f889f80b683446e498f244d0eadfd979ca5d0satokimport java.util.ArrayList;
39ae70ee49492bd89c949946562b43a75f3c81b0adsatokimport java.util.Collections;
4055aee124063dc28e740efcfdadafa5738b0b538aTadashi G. Takaokaimport java.util.Comparator;
41c88a7ff1efd10374974e45768bde1658cc1d8483satokimport java.util.HashMap;
424a5f889f80b683446e498f244d0eadfd979ca5d0satokimport java.util.List;
434a5f889f80b683446e498f244d0eadfd979ca5d0satok
445d56f6217f237ec6f1dc20a1c9f7886ca3c6a717Tadashi G. Takaokapublic class InputMethodAndSubtypeEnabler extends SettingsPreferenceFragment
455d56f6217f237ec6f1dc20a1c9f7886ca3c6a717Tadashi G. Takaoka        implements OnPreferenceChangeListener {
46c88a7ff1efd10374974e45768bde1658cc1d8483satok    private boolean mHaveHardKeyboard;
47989c364f2de3eeb2c92fa6713b8e0f137e8d971aTadashi G. Takaoka    private final HashMap<String, List<Preference>> mInputMethodAndSubtypePrefsMap =
48d2dd7d33c9206f7aa29abbff48119d0f86ddfc36Tadashi G. Takaoka            new HashMap<>();
491f53937469095f268d4c7a21d93f821a341a151dTadashi G. Takaoka    private final HashMap<String, TwoStatePreference> mAutoSelectionPrefsMap = new HashMap<>();
501c58c15e7a84b582b7d4d20c26824cabce80bce9satok    private InputMethodManager mImm;
5172c2a6e5c2990df7f36c4f7305d4ba4b28e10023Tadashi G. Takaoka    // TODO: Change mInputMethodInfoList to Map
5272c2a6e5c2990df7f36c4f7305d4ba4b28e10023Tadashi G. Takaoka    private List<InputMethodInfo> mInputMethodInfoList;
53989c364f2de3eeb2c92fa6713b8e0f137e8d971aTadashi G. Takaoka    private Collator mCollator;
544a5f889f80b683446e498f244d0eadfd979ca5d0satok
554a5f889f80b683446e498f244d0eadfd979ca5d0satok    @Override
5672c2a6e5c2990df7f36c4f7305d4ba4b28e10023Tadashi G. Takaoka    public void onCreate(final Bundle icicle) {
574a5f889f80b683446e498f244d0eadfd979ca5d0satok        super.onCreate(icicle);
581c58c15e7a84b582b7d4d20c26824cabce80bce9satok        mImm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
59ae70ee49492bd89c949946562b43a75f3c81b0adsatok        final Configuration config = getResources().getConfiguration();
604a5f889f80b683446e498f244d0eadfd979ca5d0satok        mHaveHardKeyboard = (config.keyboard == Configuration.KEYBOARD_QWERTY);
61649b9f19e1193547f339239afa32d569f43358fcDaisuke Miyakawa
62649b9f19e1193547f339239afa32d569f43358fcDaisuke Miyakawa        // Input method id should be available from an Intent when this preference is launched as a
63649b9f19e1193547f339239afa32d569f43358fcDaisuke Miyakawa        // single Activity (see InputMethodAndSubtypeEnablerActivity). It should be available
64649b9f19e1193547f339239afa32d569f43358fcDaisuke Miyakawa        // from a preference argument when the preference is launched as a part of the other
65649b9f19e1193547f339239afa32d569f43358fcDaisuke Miyakawa        // Activity (like a right pane of 2-pane Settings app)
66fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        final String targetImi = getStringExtraFromIntentOrArguments(
679f7320132b7a5e7def378ae754c8c708759a8670Tadashi G. Takaoka                android.provider.Settings.EXTRA_INPUT_METHOD_ID);
68649b9f19e1193547f339239afa32d569f43358fcDaisuke Miyakawa
6972c2a6e5c2990df7f36c4f7305d4ba4b28e10023Tadashi G. Takaoka        mInputMethodInfoList = mImm.getInputMethodList();
70989c364f2de3eeb2c92fa6713b8e0f137e8d971aTadashi G. Takaoka        mCollator = Collator.getInstance();
71fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka
72fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        final PreferenceScreen root = getPreferenceManager().createPreferenceScreen(getActivity());
73fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        final int imiCount = mInputMethodInfoList.size();
74fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        for (int index = 0; index < imiCount; ++index) {
75fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka            final InputMethodInfo imi = mInputMethodInfoList.get(index);
76fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka            // Add subtype preferences of this IME when it is specified or no IME is specified.
77fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka            if (imi.getId().equals(targetImi) || TextUtils.isEmpty(targetImi)) {
78fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka                addInputMethodSubtypePreferences(imi, root);
79fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka            }
80fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        }
81fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        setPreferenceScreen(root);
824a5f889f80b683446e498f244d0eadfd979ca5d0satok    }
834a5f889f80b683446e498f244d0eadfd979ca5d0satok
8472c2a6e5c2990df7f36c4f7305d4ba4b28e10023Tadashi G. Takaoka    private String getStringExtraFromIntentOrArguments(final String name) {
8572c2a6e5c2990df7f36c4f7305d4ba4b28e10023Tadashi G. Takaoka        final Intent intent = getActivity().getIntent();
8672c2a6e5c2990df7f36c4f7305d4ba4b28e10023Tadashi G. Takaoka        final String fromIntent = intent.getStringExtra(name);
8772c2a6e5c2990df7f36c4f7305d4ba4b28e10023Tadashi G. Takaoka        if (fromIntent != null) {
8872c2a6e5c2990df7f36c4f7305d4ba4b28e10023Tadashi G. Takaoka            return fromIntent;
8972c2a6e5c2990df7f36c4f7305d4ba4b28e10023Tadashi G. Takaoka        }
9072c2a6e5c2990df7f36c4f7305d4ba4b28e10023Tadashi G. Takaoka        final Bundle arguments = getArguments();
9172c2a6e5c2990df7f36c4f7305d4ba4b28e10023Tadashi G. Takaoka        return (arguments == null) ? null : arguments.getString(name);
9272c2a6e5c2990df7f36c4f7305d4ba4b28e10023Tadashi G. Takaoka    }
9372c2a6e5c2990df7f36c4f7305d4ba4b28e10023Tadashi G. Takaoka
944a5f889f80b683446e498f244d0eadfd979ca5d0satok    @Override
9572c2a6e5c2990df7f36c4f7305d4ba4b28e10023Tadashi G. Takaoka    public void onActivityCreated(final Bundle icicle) {
9616c3e74d72ec2d18aff007cb88fcf02995918a90satok        super.onActivityCreated(icicle);
9772c2a6e5c2990df7f36c4f7305d4ba4b28e10023Tadashi G. Takaoka        final String title = getStringExtraFromIntentOrArguments(Intent.EXTRA_TITLE);
9872c2a6e5c2990df7f36c4f7305d4ba4b28e10023Tadashi G. Takaoka        if (!TextUtils.isEmpty(title)) {
9972c2a6e5c2990df7f36c4f7305d4ba4b28e10023Tadashi G. Takaoka            getActivity().setTitle(title);
10016c3e74d72ec2d18aff007cb88fcf02995918a90satok        }
10116c3e74d72ec2d18aff007cb88fcf02995918a90satok    }
10216c3e74d72ec2d18aff007cb88fcf02995918a90satok
10316c3e74d72ec2d18aff007cb88fcf02995918a90satok    @Override
1044a5f889f80b683446e498f244d0eadfd979ca5d0satok    public void onResume() {
1054a5f889f80b683446e498f244d0eadfd979ca5d0satok        super.onResume();
106cabde98bcddc2c609a5929b019ebe73f1a68e004Satoshi Kataoka        // Refresh internal states in mInputMethodSettingValues to keep the latest
107cabde98bcddc2c609a5929b019ebe73f1a68e004Satoshi Kataoka        // "InputMethodInfo"s and "InputMethodSubtype"s
108cabde98bcddc2c609a5929b019ebe73f1a68e004Satoshi Kataoka        InputMethodSettingValuesWrapper
109cabde98bcddc2c609a5929b019ebe73f1a68e004Satoshi Kataoka                .getInstance(getActivity()).refreshAllInputMethodAndSubtypes();
1100417e4094713c5f4dac700b645000d0959bf62fasatok        InputMethodAndSubtypeUtil.loadInputMethodSubtypeList(
11172c2a6e5c2990df7f36c4f7305d4ba4b28e10023Tadashi G. Takaoka                this, getContentResolver(), mInputMethodInfoList, mInputMethodAndSubtypePrefsMap);
112989c364f2de3eeb2c92fa6713b8e0f137e8d971aTadashi G. Takaoka        updateAutoSelectionPreferences();
1134a5f889f80b683446e498f244d0eadfd979ca5d0satok    }
1144a5f889f80b683446e498f244d0eadfd979ca5d0satok
1154a5f889f80b683446e498f244d0eadfd979ca5d0satok    @Override
1164a5f889f80b683446e498f244d0eadfd979ca5d0satok    public void onPause() {
1174a5f889f80b683446e498f244d0eadfd979ca5d0satok        super.onPause();
1181c58c15e7a84b582b7d4d20c26824cabce80bce9satok        // Clear all subtypes of all IMEs to make sure
119989c364f2de3eeb2c92fa6713b8e0f137e8d971aTadashi G. Takaoka        updateImplicitlyEnabledSubtypes(null /* targetImiId */, false /* check */);
1200417e4094713c5f4dac700b645000d0959bf62fasatok        InputMethodAndSubtypeUtil.saveInputMethodSubtypeList(this, getContentResolver(),
12172c2a6e5c2990df7f36c4f7305d4ba4b28e10023Tadashi G. Takaoka                mInputMethodInfoList, mHaveHardKeyboard);
1224a5f889f80b683446e498f244d0eadfd979ca5d0satok    }
1234a5f889f80b683446e498f244d0eadfd979ca5d0satok
1244a5f889f80b683446e498f244d0eadfd979ca5d0satok    @Override
1255d56f6217f237ec6f1dc20a1c9f7886ca3c6a717Tadashi G. Takaoka    public boolean onPreferenceChange(final Preference pref, final Object newValue) {
1265d56f6217f237ec6f1dc20a1c9f7886ca3c6a717Tadashi G. Takaoka        if (!(newValue instanceof Boolean)) {
1275d56f6217f237ec6f1dc20a1c9f7886ca3c6a717Tadashi G. Takaoka            return true; // Invoke default behavior.
128fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        }
1295d56f6217f237ec6f1dc20a1c9f7886ca3c6a717Tadashi G. Takaoka        final boolean isChecking = (Boolean) newValue;
130fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        for (final String imiId : mAutoSelectionPrefsMap.keySet()) {
1315d56f6217f237ec6f1dc20a1c9f7886ca3c6a717Tadashi G. Takaoka            // An auto select subtype preference is changing.
1325d56f6217f237ec6f1dc20a1c9f7886ca3c6a717Tadashi G. Takaoka            if (mAutoSelectionPrefsMap.get(imiId) == pref) {
1331f53937469095f268d4c7a21d93f821a341a151dTadashi G. Takaoka                final TwoStatePreference autoSelectionPref = (TwoStatePreference) pref;
1345d56f6217f237ec6f1dc20a1c9f7886ca3c6a717Tadashi G. Takaoka                autoSelectionPref.setChecked(isChecking);
1355d56f6217f237ec6f1dc20a1c9f7886ca3c6a717Tadashi G. Takaoka                // Enable or disable subtypes depending on the auto selection preference.
1365d56f6217f237ec6f1dc20a1c9f7886ca3c6a717Tadashi G. Takaoka                setAutoSelectionSubtypesEnabled(imiId, autoSelectionPref.isChecked());
1375d56f6217f237ec6f1dc20a1c9f7886ca3c6a717Tadashi G. Takaoka                return false;
1381c58c15e7a84b582b7d4d20c26824cabce80bce9satok            }
139fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        }
1405d56f6217f237ec6f1dc20a1c9f7886ca3c6a717Tadashi G. Takaoka        // A subtype preference is changing.
1415d56f6217f237ec6f1dc20a1c9f7886ca3c6a717Tadashi G. Takaoka        if (pref instanceof InputMethodSubtypePreference) {
1425d56f6217f237ec6f1dc20a1c9f7886ca3c6a717Tadashi G. Takaoka            final InputMethodSubtypePreference subtypePref = (InputMethodSubtypePreference) pref;
1435d56f6217f237ec6f1dc20a1c9f7886ca3c6a717Tadashi G. Takaoka            subtypePref.setChecked(isChecking);
1445d56f6217f237ec6f1dc20a1c9f7886ca3c6a717Tadashi G. Takaoka            if (!subtypePref.isChecked()) {
1455d56f6217f237ec6f1dc20a1c9f7886ca3c6a717Tadashi G. Takaoka                // It takes care of the case where no subtypes are explicitly enabled then the auto
1465d56f6217f237ec6f1dc20a1c9f7886ca3c6a717Tadashi G. Takaoka                // selection preference is going to be checked.
1475d56f6217f237ec6f1dc20a1c9f7886ca3c6a717Tadashi G. Takaoka                updateAutoSelectionPreferences();
1485d56f6217f237ec6f1dc20a1c9f7886ca3c6a717Tadashi G. Takaoka            }
1495d56f6217f237ec6f1dc20a1c9f7886ca3c6a717Tadashi G. Takaoka            return false;
150fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        }
1515d56f6217f237ec6f1dc20a1c9f7886ca3c6a717Tadashi G. Takaoka        return true; // Invoke default behavior.
1524a5f889f80b683446e498f244d0eadfd979ca5d0satok    }
1534a5f889f80b683446e498f244d0eadfd979ca5d0satok
154fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka    private void addInputMethodSubtypePreferences(final InputMethodInfo imi,
155fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka            final PreferenceScreen root) {
156f0ae329740eb66663b6f099ca24a13ea7572418csatok        final Context context = getActivity();
157fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        final int subtypeCount = imi.getSubtypeCount();
158fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        if (subtypeCount <= 1) {
159fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka            return;
160fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        }
161fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        final String imiId = imi.getId();
162fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        final PreferenceCategory keyboardSettingsCategory = new PreferenceCategory(context);
163fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        root.addPreference(keyboardSettingsCategory);
164fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        final PackageManager pm = getPackageManager();
165fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        final CharSequence label = imi.loadLabel(pm);
1664a5f889f80b683446e498f244d0eadfd979ca5d0satok
167fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        keyboardSettingsCategory.setTitle(label);
168fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        keyboardSettingsCategory.setKey(imiId);
169fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        // TODO: Use toggle Preference if images are ready.
1701f53937469095f268d4c7a21d93f821a341a151dTadashi G. Takaoka        final TwoStatePreference autoSelectionPref = new SwitchWithNoTextPreference(context);
171fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        mAutoSelectionPrefsMap.put(imiId, autoSelectionPref);
172fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        keyboardSettingsCategory.addPreference(autoSelectionPref);
1735d56f6217f237ec6f1dc20a1c9f7886ca3c6a717Tadashi G. Takaoka        autoSelectionPref.setOnPreferenceChangeListener(this);
1741c58c15e7a84b582b7d4d20c26824cabce80bce9satok
175fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        final PreferenceCategory activeInputMethodsCategory = new PreferenceCategory(context);
176fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        activeInputMethodsCategory.setTitle(R.string.active_input_method_subtypes);
177fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        root.addPreference(activeInputMethodsCategory);
1784a5f889f80b683446e498f244d0eadfd979ca5d0satok
179fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        CharSequence autoSubtypeLabel = null;
180fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        final ArrayList<Preference> subtypePreferences = new ArrayList<>();
181fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        for (int index = 0; index < subtypeCount; ++index) {
182fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka            final InputMethodSubtype subtype = imi.getSubtypeAt(index);
183fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka            if (subtype.overridesImplicitlyEnabledSubtype()) {
184fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka                if (autoSubtypeLabel == null) {
185fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka                    autoSubtypeLabel = subtype.getDisplayName(
186fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka                            context, imi.getPackageName(), imi.getServiceInfo().applicationInfo);
1874a5f889f80b683446e498f244d0eadfd979ca5d0satok                }
188fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka            } else {
189fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka                final Preference subtypePref = new InputMethodSubtypePreference(
190fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka                        context, subtype, imi);
191fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka                subtypePreferences.add(subtypePref);
192989c364f2de3eeb2c92fa6713b8e0f137e8d971aTadashi G. Takaoka            }
193fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        }
194fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        Collections.sort(subtypePreferences, new Comparator<Preference>() {
195fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka            @Override
196fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka            public int compare(final Preference lhs, final Preference rhs) {
197fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka                if (lhs instanceof InputMethodSubtypePreference) {
198fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka                    return ((InputMethodSubtypePreference) lhs).compareTo(rhs, mCollator);
199ae70ee49492bd89c949946562b43a75f3c81b0adsatok                }
200fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka                return lhs.compareTo(rhs);
20194bc76f1aa887e90b31f375cb1e9a2ecc3c59c8bsatok            }
202fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        });
203fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        final int prefCount = subtypePreferences.size();
204fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        for (int index = 0; index < prefCount; ++index) {
205fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka            final Preference pref = subtypePreferences.get(index);
206fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka            activeInputMethodsCategory.addPreference(pref);
2075d56f6217f237ec6f1dc20a1c9f7886ca3c6a717Tadashi G. Takaoka            pref.setOnPreferenceChangeListener(this);
2083460a2683ca820d8d7d184bc1e98241ea3986a4aTadashi G. Takaoka            InputMethodAndSubtypeUtil.removeUnnecessaryNonPersistentPreference(pref);
209fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        }
210fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        mInputMethodAndSubtypePrefsMap.put(imiId, subtypePreferences);
211fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        if (TextUtils.isEmpty(autoSubtypeLabel)) {
212fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka            autoSelectionPref.setTitle(
213fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka                    R.string.use_system_language_to_select_input_method_subtypes);
214fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        } else {
215fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka            autoSelectionPref.setTitle(autoSubtypeLabel);
2164a5f889f80b683446e498f244d0eadfd979ca5d0satok        }
2174a5f889f80b683446e498f244d0eadfd979ca5d0satok    }
2181c58c15e7a84b582b7d4d20c26824cabce80bce9satok
219989c364f2de3eeb2c92fa6713b8e0f137e8d971aTadashi G. Takaoka    private boolean isNoSubtypesExplicitlySelected(final String imiId) {
2201c58c15e7a84b582b7d4d20c26824cabce80bce9satok        final List<Preference> subtypePrefs = mInputMethodAndSubtypePrefsMap.get(imiId);
22172c2a6e5c2990df7f36c4f7305d4ba4b28e10023Tadashi G. Takaoka        for (final Preference pref : subtypePrefs) {
2221f53937469095f268d4c7a21d93f821a341a151dTadashi G. Takaoka            if (pref instanceof TwoStatePreference && ((TwoStatePreference)pref).isChecked()) {
223989c364f2de3eeb2c92fa6713b8e0f137e8d971aTadashi G. Takaoka                return false;
2241c58c15e7a84b582b7d4d20c26824cabce80bce9satok            }
2251c58c15e7a84b582b7d4d20c26824cabce80bce9satok        }
226989c364f2de3eeb2c92fa6713b8e0f137e8d971aTadashi G. Takaoka        return true;
2271c58c15e7a84b582b7d4d20c26824cabce80bce9satok    }
2281c58c15e7a84b582b7d4d20c26824cabce80bce9satok
229989c364f2de3eeb2c92fa6713b8e0f137e8d971aTadashi G. Takaoka    private void setAutoSelectionSubtypesEnabled(final String imiId,
230989c364f2de3eeb2c92fa6713b8e0f137e8d971aTadashi G. Takaoka            final boolean autoSelectionEnabled) {
2311f53937469095f268d4c7a21d93f821a341a151dTadashi G. Takaoka        final TwoStatePreference autoSelectionPref = mAutoSelectionPrefsMap.get(imiId);
232989c364f2de3eeb2c92fa6713b8e0f137e8d971aTadashi G. Takaoka        if (autoSelectionPref == null) {
23372c2a6e5c2990df7f36c4f7305d4ba4b28e10023Tadashi G. Takaoka            return;
23472c2a6e5c2990df7f36c4f7305d4ba4b28e10023Tadashi G. Takaoka        }
235989c364f2de3eeb2c92fa6713b8e0f137e8d971aTadashi G. Takaoka        autoSelectionPref.setChecked(autoSelectionEnabled);
2361c58c15e7a84b582b7d4d20c26824cabce80bce9satok        final List<Preference> subtypePrefs = mInputMethodAndSubtypePrefsMap.get(imiId);
237989c364f2de3eeb2c92fa6713b8e0f137e8d971aTadashi G. Takaoka        for (final Preference pref : subtypePrefs) {
2381f53937469095f268d4c7a21d93f821a341a151dTadashi G. Takaoka            if (pref instanceof TwoStatePreference) {
2391c58c15e7a84b582b7d4d20c26824cabce80bce9satok                // When autoSelectionEnabled is true, all subtype prefs need to be disabled with
2401c58c15e7a84b582b7d4d20c26824cabce80bce9satok                // implicitly checked subtypes. In case of false, all subtype prefs need to be
2411c58c15e7a84b582b7d4d20c26824cabce80bce9satok                // enabled.
242989c364f2de3eeb2c92fa6713b8e0f137e8d971aTadashi G. Takaoka                pref.setEnabled(!autoSelectionEnabled);
2431c58c15e7a84b582b7d4d20c26824cabce80bce9satok                if (autoSelectionEnabled) {
2441f53937469095f268d4c7a21d93f821a341a151dTadashi G. Takaoka                    ((TwoStatePreference)pref).setChecked(false);
2451c58c15e7a84b582b7d4d20c26824cabce80bce9satok                }
2461c58c15e7a84b582b7d4d20c26824cabce80bce9satok            }
2471c58c15e7a84b582b7d4d20c26824cabce80bce9satok        }
2481c58c15e7a84b582b7d4d20c26824cabce80bce9satok        if (autoSelectionEnabled) {
24972c2a6e5c2990df7f36c4f7305d4ba4b28e10023Tadashi G. Takaoka            InputMethodAndSubtypeUtil.saveInputMethodSubtypeList(
25072c2a6e5c2990df7f36c4f7305d4ba4b28e10023Tadashi G. Takaoka                    this, getContentResolver(), mInputMethodInfoList, mHaveHardKeyboard);
251989c364f2de3eeb2c92fa6713b8e0f137e8d971aTadashi G. Takaoka            updateImplicitlyEnabledSubtypes(imiId, true /* check */);
2521c58c15e7a84b582b7d4d20c26824cabce80bce9satok        }
2531c58c15e7a84b582b7d4d20c26824cabce80bce9satok    }
2541c58c15e7a84b582b7d4d20c26824cabce80bce9satok
255989c364f2de3eeb2c92fa6713b8e0f137e8d971aTadashi G. Takaoka    private void updateImplicitlyEnabledSubtypes(final String targetImiId, final boolean check) {
2561c58c15e7a84b582b7d4d20c26824cabce80bce9satok        // When targetImiId is null, apply to all subtypes of all IMEs
25772c2a6e5c2990df7f36c4f7305d4ba4b28e10023Tadashi G. Takaoka        for (final InputMethodInfo imi : mInputMethodInfoList) {
25872c2a6e5c2990df7f36c4f7305d4ba4b28e10023Tadashi G. Takaoka            final String imiId = imi.getId();
2591f53937469095f268d4c7a21d93f821a341a151dTadashi G. Takaoka            final TwoStatePreference autoSelectionPref = mAutoSelectionPrefsMap.get(imiId);
2601c58c15e7a84b582b7d4d20c26824cabce80bce9satok            // No need to update implicitly enabled subtypes when the user has unchecked the
2611c58c15e7a84b582b7d4d20c26824cabce80bce9satok            // "subtype auto selection".
262989c364f2de3eeb2c92fa6713b8e0f137e8d971aTadashi G. Takaoka            if (autoSelectionPref == null || !autoSelectionPref.isChecked()) {
26372c2a6e5c2990df7f36c4f7305d4ba4b28e10023Tadashi G. Takaoka                continue;
26472c2a6e5c2990df7f36c4f7305d4ba4b28e10023Tadashi G. Takaoka            }
265fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka            if (imiId.equals(targetImiId) || targetImiId == null) {
266fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka                updateImplicitlyEnabledSubtypesOf(imi, check);
267fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka            }
268fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        }
269fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka    }
270fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka
271fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka    private void updateImplicitlyEnabledSubtypesOf(final InputMethodInfo imi, final boolean check) {
272fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        final String imiId = imi.getId();
273fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        final List<Preference> subtypePrefs = mInputMethodAndSubtypePrefsMap.get(imiId);
274fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        final List<InputMethodSubtype> implicitlyEnabledSubtypes =
275fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka                mImm.getEnabledInputMethodSubtypeList(imi, true);
276fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        if (subtypePrefs == null || implicitlyEnabledSubtypes == null) {
277fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka            return;
278fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        }
279fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka        for (final Preference pref : subtypePrefs) {
2801f53937469095f268d4c7a21d93f821a341a151dTadashi G. Takaoka            if (!(pref instanceof TwoStatePreference)) {
28172c2a6e5c2990df7f36c4f7305d4ba4b28e10023Tadashi G. Takaoka                continue;
28272c2a6e5c2990df7f36c4f7305d4ba4b28e10023Tadashi G. Takaoka            }
2831f53937469095f268d4c7a21d93f821a341a151dTadashi G. Takaoka            final TwoStatePreference subtypePref = (TwoStatePreference)pref;
284fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka            subtypePref.setChecked(false);
285fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka            if (check) {
286fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka                for (final InputMethodSubtype subtype : implicitlyEnabledSubtypes) {
287fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka                    final String implicitlyEnabledSubtypePrefKey = imiId + subtype.hashCode();
288fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka                    if (subtypePref.getKey().equals(implicitlyEnabledSubtypePrefKey)) {
289fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka                        subtypePref.setChecked(true);
290fc8202463e64d9e85af3c99c1d8552d4bb74b7dcTadashi G. Takaoka                        break;
2911c58c15e7a84b582b7d4d20c26824cabce80bce9satok                    }
2921c58c15e7a84b582b7d4d20c26824cabce80bce9satok                }
2931c58c15e7a84b582b7d4d20c26824cabce80bce9satok            }
2941c58c15e7a84b582b7d4d20c26824cabce80bce9satok        }
2951c58c15e7a84b582b7d4d20c26824cabce80bce9satok    }
2961c58c15e7a84b582b7d4d20c26824cabce80bce9satok
297989c364f2de3eeb2c92fa6713b8e0f137e8d971aTadashi G. Takaoka    private void updateAutoSelectionPreferences() {
29872c2a6e5c2990df7f36c4f7305d4ba4b28e10023Tadashi G. Takaoka        for (final String imiId : mInputMethodAndSubtypePrefsMap.keySet()) {
299989c364f2de3eeb2c92fa6713b8e0f137e8d971aTadashi G. Takaoka            setAutoSelectionSubtypesEnabled(imiId, isNoSubtypesExplicitlySelected(imiId));
3001c58c15e7a84b582b7d4d20c26824cabce80bce9satok        }
301989c364f2de3eeb2c92fa6713b8e0f137e8d971aTadashi G. Takaoka        updateImplicitlyEnabledSubtypes(null /* targetImiId */, true /* check */);
3021c58c15e7a84b582b7d4d20c26824cabce80bce9satok    }
3034a5f889f80b683446e498f244d0eadfd979ca5d0satok}
304