UserDictionarySettings.java revision 432fafe200a84ac519b1f23484cab55007baa62a
1/** 2 * Copyright (C) 2009 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy 6 * 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, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations 14 * under the License. 15 */ 16 17package com.android.settings; 18 19import android.app.Activity; 20import android.app.AlertDialog; 21import android.app.Dialog; 22import android.app.ListFragment; 23import android.content.ContentResolver; 24import android.content.Context; 25import android.content.DialogInterface; 26import android.content.Intent; 27import android.database.Cursor; 28import android.os.Bundle; 29import android.provider.UserDictionary; 30import android.text.InputType; 31import android.util.Log; 32import android.view.LayoutInflater; 33import android.view.Menu; 34import android.view.MenuInflater; 35import android.view.MenuItem; 36import android.view.View; 37import android.view.ViewGroup; 38import android.view.WindowManager; 39import android.widget.AlphabetIndexer; 40import android.widget.EditText; 41import android.widget.ImageView; 42import android.widget.ListAdapter; 43import android.widget.ListView; 44import android.widget.SectionIndexer; 45import android.widget.SimpleCursorAdapter; 46import android.widget.TextView; 47 48import com.android.settings.inputmethod.UserDictionaryAddWordActivity; 49 50import java.util.Locale; 51 52public class UserDictionarySettings extends ListFragment { 53 private static final String TAG = "UserDictionarySettings"; 54 55 private static final String[] QUERY_PROJECTION = { 56 UserDictionary.Words._ID, UserDictionary.Words.WORD 57 }; 58 59 private static final int INDEX_ID = 0; 60 private static final int INDEX_WORD = 1; 61 62 // Either the locale is empty (means the word is applicable to all locales) 63 // or the word equals our current locale 64 private static final String QUERY_SELECTION = 65 UserDictionary.Words.LOCALE + "=?"; 66 private static final String QUERY_SELECTION_ALL_LOCALES = 67 UserDictionary.Words.LOCALE + " is null"; 68 69 private static final String DELETE_SELECTION = UserDictionary.Words.WORD + "=?"; 70 71 private static final int OPTIONS_MENU_ADD = Menu.FIRST; 72 73 private Cursor mCursor; 74 75 protected String mLocale; 76 77 @Override 78 public void onCreate(Bundle savedInstanceState) { 79 super.onCreate(savedInstanceState); 80 } 81 82 @Override 83 public View onCreateView( 84 LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 85 return inflater.inflate( 86 com.android.internal.R.layout.preference_list_fragment, container, false); 87 } 88 89 @Override 90 public void onActivityCreated(Bundle savedInstanceState) { 91 super.onActivityCreated(savedInstanceState); 92 93 final Intent intent = getActivity().getIntent(); 94 final String localeFromIntent = 95 null == intent ? null : intent.getStringExtra("locale"); 96 97 final Bundle arguments = getArguments(); 98 final String localeFromArguments = 99 null == arguments ? null : arguments.getString("locale"); 100 101 final String locale; 102 if (null != localeFromArguments) { 103 locale = localeFromArguments; 104 } else if (null != localeFromIntent) { 105 locale = localeFromIntent; 106 } else { 107 locale = null; 108 } 109 110 mLocale = locale; 111 mCursor = createCursor(locale); 112 TextView emptyView = (TextView) getView().findViewById(android.R.id.empty); 113 emptyView.setText(R.string.user_dict_settings_empty_text); 114 115 final ListView listView = getListView(); 116 listView.setAdapter(createAdapter()); 117 listView.setFastScrollEnabled(true); 118 listView.setEmptyView(emptyView); 119 120 setHasOptionsMenu(true); 121 122 } 123 124 private Cursor createCursor(final String locale) { 125 // Locale can be any of: 126 // - The string representation of a locale, as returned by Locale#toString() 127 // - The empty string. This means we want a cursor returning words valid for all locales. 128 // - null. This means we want a cursor for the current locale, whatever this is. 129 // Note that this contrasts with the data inside the database, where NULL means "all 130 // locales" and there should never be an empty string. The confusion is called by the 131 // historical use of null for "all locales". 132 // TODO: it should be easy to make this more readable by making the special values 133 // human-readable, like "all_locales" and "current_locales" strings, provided they 134 // can be guaranteed not to match locales that may exist. 135 if ("".equals(locale)) { 136 // Case-insensitive sort 137 return getActivity().managedQuery(UserDictionary.Words.CONTENT_URI, QUERY_PROJECTION, 138 QUERY_SELECTION_ALL_LOCALES, null, 139 "UPPER(" + UserDictionary.Words.WORD + ")"); 140 } else { 141 final String queryLocale = null != locale ? locale : Locale.getDefault().toString(); 142 return getActivity().managedQuery(UserDictionary.Words.CONTENT_URI, QUERY_PROJECTION, 143 QUERY_SELECTION, new String[] { queryLocale }, 144 "UPPER(" + UserDictionary.Words.WORD + ")"); 145 } 146 } 147 148 private ListAdapter createAdapter() { 149 return new MyAdapter(getActivity(), 150 R.layout.user_dictionary_item, mCursor, 151 new String[] { UserDictionary.Words.WORD, UserDictionary.Words._ID }, 152 new int[] { android.R.id.text1, R.id.delete_button }, this); 153 } 154 155 @Override 156 public void onListItemClick(ListView l, View v, int position, long id) { 157 String word = getWord(position); 158 if (word != null) { 159 showAddOrEditDialog(word); 160 } 161 } 162 163 @Override 164 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 165 MenuItem actionItem = 166 menu.add(0, OPTIONS_MENU_ADD, 0, R.string.user_dict_settings_add_menu_title) 167 .setIcon(R.drawable.ic_menu_add); 168 actionItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM | 169 MenuItem.SHOW_AS_ACTION_WITH_TEXT); 170 } 171 172 @Override 173 public boolean onOptionsItemSelected(MenuItem item) { 174 if (item.getItemId() == OPTIONS_MENU_ADD) { 175 showAddOrEditDialog(null); 176 return true; 177 } 178 return false; 179 } 180 181 /** 182 * Add or edit a word. If editingWord is null, it's an add; otherwise, it's an edit. 183 * @param editingWord the word to edit, or null if it's an add. 184 */ 185 private void showAddOrEditDialog(final String editingWord) { 186 final Intent intent = new Intent(null == editingWord 187 ? UserDictionaryAddWordActivity.MODE_INSERT_ACTION 188 : UserDictionaryAddWordActivity.MODE_EDIT_ACTION); 189 // The following are fine if they are null 190 intent.putExtra(UserDictionaryAddWordActivity.EXTRA_WORD, editingWord); 191 intent.putExtra(UserDictionaryAddWordActivity.EXTRA_LOCALE, mLocale); 192 startActivity(intent); 193 } 194 195 private String getWord(int position) { 196 if (null == mCursor) return null; 197 mCursor.moveToPosition(position); 198 // Handle a possible race-condition 199 if (mCursor.isAfterLast()) return null; 200 201 return mCursor.getString( 202 mCursor.getColumnIndexOrThrow(UserDictionary.Words.WORD)); 203 } 204 205 public static void deleteWord(final String word, final ContentResolver resolver) { 206 resolver.delete( 207 UserDictionary.Words.CONTENT_URI, DELETE_SELECTION, new String[] { word }); 208 } 209 210 private static class MyAdapter extends SimpleCursorAdapter implements SectionIndexer, 211 View.OnClickListener { 212 213 private AlphabetIndexer mIndexer; 214 private UserDictionarySettings mSettings; 215 216 private ViewBinder mViewBinder = new ViewBinder() { 217 218 public boolean setViewValue(View v, Cursor c, int columnIndex) { 219 if (v instanceof ImageView && columnIndex == INDEX_ID) { 220 v.setOnClickListener(MyAdapter.this); 221 v.setTag(c.getString(INDEX_WORD)); 222 return true; 223 } 224 225 return false; 226 } 227 }; 228 229 public MyAdapter(Context context, int layout, Cursor c, String[] from, int[] to, 230 UserDictionarySettings settings) { 231 super(context, layout, c, from, to); 232 233 mSettings = settings; 234 if (null != c) { 235 final String alphabet = context.getString( 236 com.android.internal.R.string.fast_scroll_alphabet); 237 final int wordColIndex = c.getColumnIndexOrThrow(UserDictionary.Words.WORD); 238 mIndexer = new AlphabetIndexer(c, wordColIndex, alphabet); 239 } 240 setViewBinder(mViewBinder); 241 } 242 243 public int getPositionForSection(int section) { 244 return null == mIndexer ? 0 : mIndexer.getPositionForSection(section); 245 } 246 247 public int getSectionForPosition(int position) { 248 return null == mIndexer ? 0 : mIndexer.getSectionForPosition(position); 249 } 250 251 public Object[] getSections() { 252 return null == mIndexer ? null : mIndexer.getSections(); 253 } 254 255 public void onClick(View v) { 256 UserDictionarySettings.deleteWord((String) v.getTag(), 257 mSettings.getActivity().getContentResolver()); 258 } 259 } 260} 261