1/*
2 * Copyright (C) 2011 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
17package com.android.settings.inputmethod;
18
19import android.app.Activity;
20import android.content.Context;
21import android.content.Intent;
22import android.database.Cursor;
23import android.os.Bundle;
24import android.provider.UserDictionary;
25import android.support.v7.preference.Preference;
26import android.support.v7.preference.PreferenceGroup;
27import android.text.TextUtils;
28import android.view.inputmethod.InputMethodInfo;
29import android.view.inputmethod.InputMethodManager;
30import android.view.inputmethod.InputMethodSubtype;
31
32import com.android.internal.logging.MetricsProto.MetricsEvent;
33import com.android.settings.R;
34import com.android.settings.SettingsPreferenceFragment;
35import com.android.settings.Utils;
36
37import java.util.List;
38import java.util.Locale;
39import java.util.TreeSet;
40
41public class UserDictionaryList extends SettingsPreferenceFragment {
42    public static final String USER_DICTIONARY_SETTINGS_INTENT_ACTION =
43            "android.settings.USER_DICTIONARY_SETTINGS";
44    private String mLocale;
45
46    @Override
47    protected int getMetricsCategory() {
48        return MetricsEvent.INPUTMETHOD_USER_DICTIONARY;
49    }
50
51    @Override
52    public void onCreate(Bundle icicle) {
53        super.onCreate(icicle);
54        setPreferenceScreen(getPreferenceManager().createPreferenceScreen(getActivity()));
55    }
56
57    @Override
58    public void onActivityCreated(Bundle savedInstanceState) {
59        super.onActivityCreated(savedInstanceState);
60        getActivity().getActionBar().setTitle(R.string.user_dict_settings_title);
61
62        final Intent intent = getActivity().getIntent();
63        final String localeFromIntent =
64                null == intent ? null : intent.getStringExtra("locale");
65
66        final Bundle arguments = getArguments();
67        final String localeFromArguments =
68                null == arguments ? null : arguments.getString("locale");
69
70        final String locale;
71        if (null != localeFromArguments) {
72            locale = localeFromArguments;
73        } else if (null != localeFromIntent) {
74            locale = localeFromIntent;
75        } else {
76            locale = null;
77        }
78        mLocale = locale;
79    }
80
81    public static TreeSet<String> getUserDictionaryLocalesSet(Context context) {
82        final Cursor cursor = context.getContentResolver().query(
83                UserDictionary.Words.CONTENT_URI, new String[] { UserDictionary.Words.LOCALE },
84                null, null, null);
85        final TreeSet<String> localeSet = new TreeSet<String>();
86        if (null == cursor) {
87            // The user dictionary service is not present or disabled. Return null.
88            return null;
89        }
90        try {
91            if (cursor.moveToFirst()) {
92                final int columnIndex = cursor.getColumnIndex(UserDictionary.Words.LOCALE);
93                do {
94                    final String locale = cursor.getString(columnIndex);
95                    localeSet.add(null != locale ? locale : "");
96                } while (cursor.moveToNext());
97            }
98        } finally {
99            cursor.close();
100        }
101
102        // CAVEAT: Keep this for consistency of the implementation between Keyboard and Settings
103        // if (!UserDictionarySettings.IS_SHORTCUT_API_SUPPORTED) {
104        //     // For ICS, we need to show "For all languages" in case that the keyboard locale
105        //     // is different from the system locale
106        //     localeSet.add("");
107        // }
108
109        final InputMethodManager imm =
110                (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE);
111        final List<InputMethodInfo> imis = imm.getEnabledInputMethodList();
112        for (final InputMethodInfo imi : imis) {
113            final List<InputMethodSubtype> subtypes =
114                    imm.getEnabledInputMethodSubtypeList(
115                            imi, true /* allowsImplicitlySelectedSubtypes */);
116            for (InputMethodSubtype subtype : subtypes) {
117                final String locale = subtype.getLocale();
118                if (!TextUtils.isEmpty(locale)) {
119                    localeSet.add(locale);
120                }
121            }
122        }
123
124        // We come here after we have collected locales from existing user dictionary entries and
125        // enabled subtypes. If we already have the locale-without-country version of the system
126        // locale, we don't add the system locale to avoid confusion even though it's technically
127        // correct to add it.
128        if (!localeSet.contains(Locale.getDefault().getLanguage().toString())) {
129            localeSet.add(Locale.getDefault().toString());
130        }
131
132        return localeSet;
133    }
134
135    /**
136     * Creates the entries that allow the user to go into the user dictionary for each locale.
137     * @param userDictGroup The group to put the settings in.
138     */
139    protected void createUserDictSettings(PreferenceGroup userDictGroup) {
140        final Activity activity = getActivity();
141        userDictGroup.removeAll();
142        final TreeSet<String> localeSet =
143                UserDictionaryList.getUserDictionaryLocalesSet(activity);
144        if (mLocale != null) {
145            // If the caller explicitly specify empty string as a locale, we'll show "all languages"
146            // in the list.
147            localeSet.add(mLocale);
148        }
149        if (localeSet.size() > 1) {
150            // Have an "All languages" entry in the languages list if there are two or more active
151            // languages
152            localeSet.add("");
153        }
154
155        if (localeSet.isEmpty()) {
156            userDictGroup.addPreference(createUserDictionaryPreference(null, activity));
157        } else {
158            for (String locale : localeSet) {
159                userDictGroup.addPreference(createUserDictionaryPreference(locale, activity));
160            }
161        }
162    }
163
164    /**
165     * Create a single User Dictionary Preference object, with its parameters set.
166     * @param locale The locale for which this user dictionary is for.
167     * @return The corresponding preference.
168     */
169    protected Preference createUserDictionaryPreference(String locale, Activity activity) {
170        final Preference newPref = new Preference(getPrefContext());
171        final Intent intent = new Intent(USER_DICTIONARY_SETTINGS_INTENT_ACTION);
172        if (null == locale) {
173            newPref.setTitle(Locale.getDefault().getDisplayName());
174        } else {
175            if ("".equals(locale))
176                newPref.setTitle(getString(R.string.user_dict_settings_all_languages));
177            else
178                newPref.setTitle(Utils.createLocaleFromString(locale).getDisplayName());
179            intent.putExtra("locale", locale);
180            newPref.getExtras().putString("locale", locale);
181        }
182        newPref.setIntent(intent);
183        newPref.setFragment(com.android.settings.UserDictionarySettings.class.getName());
184        return newPref;
185    }
186
187    @Override
188    public void onResume() {
189        super.onResume();
190        createUserDictSettings(getPreferenceScreen());
191    }
192}
193