1a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka/*
2a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka * Copyright (C) 2013 The Android Open Source Project
3a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka *
4a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka * Licensed under the Apache License, Version 2.0 (the "License");
5a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka * you may not use this file except in compliance with the License.
6a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka * You may obtain a copy of the License at
7a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka *
8a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka *      http://www.apache.org/licenses/LICENSE-2.0
9a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka *
10a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka * Unless required by applicable law or agreed to in writing, software
11a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka * distributed under the License is distributed on an "AS IS" BASIS,
12a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka * See the License for the specific language governing permissions and
14a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka * limitations under the License.
15a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka */
16a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka
17a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataokapackage com.android.inputmethod.latin.userdictionary;
18a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka
19a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataokaimport android.app.Activity;
20a2bfd46adf6aca5864be3d6ef2204bc18008e9c9Satoshi Kataokaimport android.content.Context;
21a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataokaimport android.content.Intent;
22a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataokaimport android.database.Cursor;
23a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataokaimport android.os.Bundle;
24a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataokaimport android.preference.Preference;
25a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataokaimport android.preference.PreferenceFragment;
26a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataokaimport android.preference.PreferenceGroup;
27a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataokaimport android.provider.UserDictionary;
28dcef94165b256c2bc8d3a05e2fe0caf0795c7155Satoshi Kataokaimport android.text.TextUtils;
29a2bfd46adf6aca5864be3d6ef2204bc18008e9c9Satoshi Kataokaimport android.view.inputmethod.InputMethodInfo;
30a2bfd46adf6aca5864be3d6ef2204bc18008e9c9Satoshi Kataokaimport android.view.inputmethod.InputMethodManager;
31a2bfd46adf6aca5864be3d6ef2204bc18008e9c9Satoshi Kataokaimport android.view.inputmethod.InputMethodSubtype;
32a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka
33e28eba5074664d5716b8e58b8d0a235746b261ebKen Wakasaimport com.android.inputmethod.latin.R;
34e28eba5074664d5716b8e58b8d0a235746b261ebKen Wakasaimport com.android.inputmethod.latin.utils.LocaleUtils;
35e28eba5074664d5716b8e58b8d0a235746b261ebKen Wakasa
36a2bfd46adf6aca5864be3d6ef2204bc18008e9c9Satoshi Kataokaimport java.util.List;
37a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataokaimport java.util.Locale;
38a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataokaimport java.util.TreeSet;
39a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka
40a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka// Caveat: This class is basically taken from
41a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka// packages/apps/Settings/src/com/android/settings/inputmethod/UserDictionaryList.java
42a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka// in order to deal with some devices that have issues with the user dictionary handling
43a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka
44a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataokapublic class UserDictionaryList extends PreferenceFragment {
45a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka
46a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka    public static final String USER_DICTIONARY_SETTINGS_INTENT_ACTION =
47a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka            "android.settings.USER_DICTIONARY_SETTINGS";
48a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka
49a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka    @Override
50a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka    public void onCreate(Bundle icicle) {
51a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka        super.onCreate(icicle);
52a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka        setPreferenceScreen(getPreferenceManager().createPreferenceScreen(getActivity()));
53a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka    }
54a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka
55a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka    public static TreeSet<String> getUserDictionaryLocalesSet(Activity activity) {
56c44b7312ad60c76ddd1c303d10b4f8e66ea9e605Jean Chalard        final Cursor cursor = activity.getContentResolver().query(UserDictionary.Words.CONTENT_URI,
57a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka                new String[] { UserDictionary.Words.LOCALE },
58a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka                null, null, null);
59a91561aa58db1c43092c1caecc051a11fa5391c7Tadashi G. Takaoka        final TreeSet<String> localeSet = new TreeSet<>();
60a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka        if (null == cursor) {
61a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka            // The user dictionary service is not present or disabled. Return null.
62a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka            return null;
63b8ff8ca9d9d17f61f3f0e019ed0b62fe13d1a33fJean Chalard        }
64b8ff8ca9d9d17f61f3f0e019ed0b62fe13d1a33fJean Chalard        try {
65b8ff8ca9d9d17f61f3f0e019ed0b62fe13d1a33fJean Chalard            if (cursor.moveToFirst()) {
66b8ff8ca9d9d17f61f3f0e019ed0b62fe13d1a33fJean Chalard                final int columnIndex = cursor.getColumnIndex(UserDictionary.Words.LOCALE);
67b8ff8ca9d9d17f61f3f0e019ed0b62fe13d1a33fJean Chalard                do {
68b8ff8ca9d9d17f61f3f0e019ed0b62fe13d1a33fJean Chalard                    final String locale = cursor.getString(columnIndex);
69b8ff8ca9d9d17f61f3f0e019ed0b62fe13d1a33fJean Chalard                    localeSet.add(null != locale ? locale : "");
70b8ff8ca9d9d17f61f3f0e019ed0b62fe13d1a33fJean Chalard                } while (cursor.moveToNext());
71b8ff8ca9d9d17f61f3f0e019ed0b62fe13d1a33fJean Chalard            }
72b8ff8ca9d9d17f61f3f0e019ed0b62fe13d1a33fJean Chalard        } finally {
73b8ff8ca9d9d17f61f3f0e019ed0b62fe13d1a33fJean Chalard            cursor.close();
74a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka        }
754ded1af21097652dcd0750d9b3f2f24df2904e25Satoshi Kataoka        if (!UserDictionarySettings.IS_SHORTCUT_API_SUPPORTED) {
76dcef94165b256c2bc8d3a05e2fe0caf0795c7155Satoshi Kataoka            // For ICS, we need to show "For all languages" in case that the keyboard locale
77dcef94165b256c2bc8d3a05e2fe0caf0795c7155Satoshi Kataoka            // is different from the system locale
78a2bfd46adf6aca5864be3d6ef2204bc18008e9c9Satoshi Kataoka            localeSet.add("");
79dcef94165b256c2bc8d3a05e2fe0caf0795c7155Satoshi Kataoka        }
80a2bfd46adf6aca5864be3d6ef2204bc18008e9c9Satoshi Kataoka
81a2bfd46adf6aca5864be3d6ef2204bc18008e9c9Satoshi Kataoka        final InputMethodManager imm =
82a2bfd46adf6aca5864be3d6ef2204bc18008e9c9Satoshi Kataoka                (InputMethodManager)activity.getSystemService(Context.INPUT_METHOD_SERVICE);
83a2bfd46adf6aca5864be3d6ef2204bc18008e9c9Satoshi Kataoka        final List<InputMethodInfo> imis = imm.getEnabledInputMethodList();
84a2bfd46adf6aca5864be3d6ef2204bc18008e9c9Satoshi Kataoka        for (final InputMethodInfo imi : imis) {
85a2bfd46adf6aca5864be3d6ef2204bc18008e9c9Satoshi Kataoka            final List<InputMethodSubtype> subtypes =
86a2bfd46adf6aca5864be3d6ef2204bc18008e9c9Satoshi Kataoka                    imm.getEnabledInputMethodSubtypeList(
87a2bfd46adf6aca5864be3d6ef2204bc18008e9c9Satoshi Kataoka                            imi, true /* allowsImplicitlySelectedSubtypes */);
88a2bfd46adf6aca5864be3d6ef2204bc18008e9c9Satoshi Kataoka            for (InputMethodSubtype subtype : subtypes) {
89a2bfd46adf6aca5864be3d6ef2204bc18008e9c9Satoshi Kataoka                final String locale = subtype.getLocale();
90a2bfd46adf6aca5864be3d6ef2204bc18008e9c9Satoshi Kataoka                if (!TextUtils.isEmpty(locale)) {
91a2bfd46adf6aca5864be3d6ef2204bc18008e9c9Satoshi Kataoka                    localeSet.add(locale);
92a2bfd46adf6aca5864be3d6ef2204bc18008e9c9Satoshi Kataoka                }
93a2bfd46adf6aca5864be3d6ef2204bc18008e9c9Satoshi Kataoka            }
94a2bfd46adf6aca5864be3d6ef2204bc18008e9c9Satoshi Kataoka        }
95a2bfd46adf6aca5864be3d6ef2204bc18008e9c9Satoshi Kataoka
96a2bfd46adf6aca5864be3d6ef2204bc18008e9c9Satoshi Kataoka        // We come here after we have collected locales from existing user dictionary entries and
97a2bfd46adf6aca5864be3d6ef2204bc18008e9c9Satoshi Kataoka        // enabled subtypes. If we already have the locale-without-country version of the system
98a2bfd46adf6aca5864be3d6ef2204bc18008e9c9Satoshi Kataoka        // locale, we don't add the system locale to avoid confusion even though it's technically
99a2bfd46adf6aca5864be3d6ef2204bc18008e9c9Satoshi Kataoka        // correct to add it.
100a2bfd46adf6aca5864be3d6ef2204bc18008e9c9Satoshi Kataoka        if (!localeSet.contains(Locale.getDefault().getLanguage().toString())) {
101a2bfd46adf6aca5864be3d6ef2204bc18008e9c9Satoshi Kataoka            localeSet.add(Locale.getDefault().toString());
102a2bfd46adf6aca5864be3d6ef2204bc18008e9c9Satoshi Kataoka        }
103a2bfd46adf6aca5864be3d6ef2204bc18008e9c9Satoshi Kataoka
104a2bfd46adf6aca5864be3d6ef2204bc18008e9c9Satoshi Kataoka        return localeSet;
105a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka    }
106a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka
107a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka    /**
108a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka     * Creates the entries that allow the user to go into the user dictionary for each locale.
109a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka     * @param userDictGroup The group to put the settings in.
110a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka     */
111a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka    protected void createUserDictSettings(PreferenceGroup userDictGroup) {
112a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka        final Activity activity = getActivity();
113a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka        userDictGroup.removeAll();
1145563dc3ad51a350f67ad857991aa97623a0084b8Satoshi Kataoka        final TreeSet<String> localeSet =
115a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka                UserDictionaryList.getUserDictionaryLocalesSet(activity);
116a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka
1175563dc3ad51a350f67ad857991aa97623a0084b8Satoshi Kataoka        if (localeSet.size() > 1) {
1185563dc3ad51a350f67ad857991aa97623a0084b8Satoshi Kataoka            // Have an "All languages" entry in the languages list if there are two or more active
1195563dc3ad51a350f67ad857991aa97623a0084b8Satoshi Kataoka            // languages
1205563dc3ad51a350f67ad857991aa97623a0084b8Satoshi Kataoka            localeSet.add("");
1215563dc3ad51a350f67ad857991aa97623a0084b8Satoshi Kataoka        }
1225563dc3ad51a350f67ad857991aa97623a0084b8Satoshi Kataoka
1235563dc3ad51a350f67ad857991aa97623a0084b8Satoshi Kataoka        if (localeSet.isEmpty()) {
124a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka            userDictGroup.addPreference(createUserDictionaryPreference(null, activity));
125a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka        } else {
1265563dc3ad51a350f67ad857991aa97623a0084b8Satoshi Kataoka            for (String locale : localeSet) {
127a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka                userDictGroup.addPreference(createUserDictionaryPreference(locale, activity));
128a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka            }
129a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka        }
130a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka    }
131a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka
132a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka    /**
133a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka     * Create a single User Dictionary Preference object, with its parameters set.
134a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka     * @param locale The locale for which this user dictionary is for.
135a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka     * @return The corresponding preference.
136a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka     */
137a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka    protected Preference createUserDictionaryPreference(String locale, Activity activity) {
138a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka        final Preference newPref = new Preference(getActivity());
139a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka        final Intent intent = new Intent(USER_DICTIONARY_SETTINGS_INTENT_ACTION);
140a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka        if (null == locale) {
141a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka            newPref.setTitle(Locale.getDefault().getDisplayName());
142a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka        } else {
143a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka            if ("".equals(locale))
144a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka                newPref.setTitle(getString(R.string.user_dict_settings_all_languages));
145a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka            else
146a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka                newPref.setTitle(LocaleUtils.constructLocaleFromString(locale).getDisplayName());
147a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka            intent.putExtra("locale", locale);
148a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka            newPref.getExtras().putString("locale", locale);
149a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka        }
150a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka        newPref.setIntent(intent);
151a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka        newPref.setFragment(UserDictionarySettings.class.getName());
152a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka        return newPref;
153a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka    }
154a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka
155a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka    @Override
156a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka    public void onResume() {
157a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka        super.onResume();
158a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka        createUserDictSettings(getPreferenceScreen());
159a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka    }
160a79ba8a3d6dbdee777f156449c436fd3a4a57febSatoshi Kataoka}
161