UserDictionarySettings.java revision 1571c0a377f4aa94ef424da326a52fad638b3e54
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.text.TextUtils; 32import android.util.Log; 33import android.view.LayoutInflater; 34import android.view.Menu; 35import android.view.MenuInflater; 36import android.view.MenuItem; 37import android.view.View; 38import android.view.ViewGroup; 39import android.view.WindowManager; 40import android.widget.AlphabetIndexer; 41import android.widget.EditText; 42import android.widget.ImageView; 43import android.widget.ListAdapter; 44import android.widget.ListView; 45import android.widget.SectionIndexer; 46import android.widget.SimpleCursorAdapter; 47import android.widget.TextView; 48 49import com.android.settings.inputmethod.UserDictionaryAddWordContents; 50 51import java.util.Locale; 52 53public class UserDictionarySettings extends ListFragment { 54 private static final String TAG = "UserDictionarySettings"; 55 56 private static final String[] QUERY_PROJECTION = { 57 UserDictionary.Words._ID, UserDictionary.Words.WORD, UserDictionary.Words.SHORTCUT 58 }; 59 60 // The index of the shortcut in the above array. 61 private static final int INDEX_SHORTCUT = 2; 62 63 // Either the locale is empty (means the word is applicable to all locales) 64 // or the word equals our current locale 65 private static final String QUERY_SELECTION = 66 UserDictionary.Words.LOCALE + "=?"; 67 private static final String QUERY_SELECTION_ALL_LOCALES = 68 UserDictionary.Words.LOCALE + " is null"; 69 70 private static final String DELETE_SELECTION = UserDictionary.Words.WORD + "=?"; 71 72 private static final int OPTIONS_MENU_ADD = Menu.FIRST; 73 74 private Cursor mCursor; 75 76 protected String mLocale; 77 78 @Override 79 public void onCreate(Bundle savedInstanceState) { 80 super.onCreate(savedInstanceState); 81 } 82 83 @Override 84 public View onCreateView( 85 LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 86 return inflater.inflate( 87 com.android.internal.R.layout.preference_list_fragment, container, false); 88 } 89 90 @Override 91 public void onActivityCreated(Bundle savedInstanceState) { 92 super.onActivityCreated(savedInstanceState); 93 94 final Intent intent = getActivity().getIntent(); 95 final String localeFromIntent = 96 null == intent ? null : intent.getStringExtra("locale"); 97 98 final Bundle arguments = getArguments(); 99 final String localeFromArguments = 100 null == arguments ? null : arguments.getString("locale"); 101 102 final String locale; 103 if (null != localeFromArguments) { 104 locale = localeFromArguments; 105 } else if (null != localeFromIntent) { 106 locale = localeFromIntent; 107 } else { 108 locale = null; 109 } 110 111 mLocale = locale; 112 mCursor = createCursor(locale); 113 TextView emptyView = (TextView) getView().findViewById(android.R.id.empty); 114 emptyView.setText(R.string.user_dict_settings_empty_text); 115 116 final ListView listView = getListView(); 117 listView.setAdapter(createAdapter()); 118 listView.setFastScrollEnabled(true); 119 listView.setEmptyView(emptyView); 120 121 setHasOptionsMenu(true); 122 123 } 124 125 private Cursor createCursor(final String locale) { 126 // Locale can be any of: 127 // - The string representation of a locale, as returned by Locale#toString() 128 // - The empty string. This means we want a cursor returning words valid for all locales. 129 // - null. This means we want a cursor for the current locale, whatever this is. 130 // Note that this contrasts with the data inside the database, where NULL means "all 131 // locales" and there should never be an empty string. The confusion is called by the 132 // historical use of null for "all locales". 133 // TODO: it should be easy to make this more readable by making the special values 134 // human-readable, like "all_locales" and "current_locales" strings, provided they 135 // can be guaranteed not to match locales that may exist. 136 if ("".equals(locale)) { 137 // Case-insensitive sort 138 return getActivity().managedQuery(UserDictionary.Words.CONTENT_URI, QUERY_PROJECTION, 139 QUERY_SELECTION_ALL_LOCALES, null, 140 "UPPER(" + UserDictionary.Words.WORD + ")"); 141 } else { 142 final String queryLocale = null != locale ? locale : Locale.getDefault().toString(); 143 return getActivity().managedQuery(UserDictionary.Words.CONTENT_URI, QUERY_PROJECTION, 144 QUERY_SELECTION, new String[] { queryLocale }, 145 "UPPER(" + UserDictionary.Words.WORD + ")"); 146 } 147 } 148 149 private ListAdapter createAdapter() { 150 return new MyAdapter(getActivity(), 151 R.layout.user_dictionary_item, mCursor, 152 new String[] { UserDictionary.Words.WORD, UserDictionary.Words.SHORTCUT }, 153 new int[] { android.R.id.text1, android.R.id.text2 }, this); 154 } 155 156 @Override 157 public void onListItemClick(ListView l, View v, int position, long id) { 158 final String word = getWord(position); 159 final String shortcut = getShortcut(position); 160 if (word != null) { 161 showAddOrEditDialog(word, shortcut); 162 } 163 } 164 165 @Override 166 public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 167 MenuItem actionItem = 168 menu.add(0, OPTIONS_MENU_ADD, 0, R.string.user_dict_settings_add_menu_title) 169 .setIcon(R.drawable.ic_menu_add); 170 actionItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM | 171 MenuItem.SHOW_AS_ACTION_WITH_TEXT); 172 } 173 174 @Override 175 public boolean onOptionsItemSelected(MenuItem item) { 176 if (item.getItemId() == OPTIONS_MENU_ADD) { 177 showAddOrEditDialog(null, null); 178 return true; 179 } 180 return false; 181 } 182 183 /** 184 * Add or edit a word. If editingWord is null, it's an add; otherwise, it's an edit. 185 * @param editingWord the word to edit, or null if it's an add. 186 * @param editingShortcut the shortcut for this entry, or null if none. 187 */ 188 private void showAddOrEditDialog(final String editingWord, final String editingShortcut) { 189 final Bundle args = new Bundle(); 190 args.putInt(UserDictionaryAddWordContents.EXTRA_MODE, null == editingWord 191 ? UserDictionaryAddWordContents.MODE_INSERT 192 : UserDictionaryAddWordContents.MODE_EDIT); 193 args.putString(UserDictionaryAddWordContents.EXTRA_WORD, editingWord); 194 args.putString(UserDictionaryAddWordContents.EXTRA_SHORTCUT, editingShortcut); 195 args.putString(UserDictionaryAddWordContents.EXTRA_LOCALE, mLocale); 196 android.preference.PreferenceActivity pa = 197 (android.preference.PreferenceActivity)getActivity(); 198 pa.startPreferencePanel( 199 com.android.settings.inputmethod.UserDictionaryAddWordFragment.class.getName(), 200 args, R.string.details_title, null, null, 0); 201 } 202 203 private String getWord(final int position) { 204 if (null == mCursor) return null; 205 mCursor.moveToPosition(position); 206 // Handle a possible race-condition 207 if (mCursor.isAfterLast()) return null; 208 209 return mCursor.getString( 210 mCursor.getColumnIndexOrThrow(UserDictionary.Words.WORD)); 211 } 212 213 private String getShortcut(final int position) { 214 if (null == mCursor) return null; 215 mCursor.moveToPosition(position); 216 // Handle a possible race-condition 217 if (mCursor.isAfterLast()) return null; 218 219 return mCursor.getString( 220 mCursor.getColumnIndexOrThrow(UserDictionary.Words.SHORTCUT)); 221 } 222 223 public static void deleteWord(final String word, final ContentResolver resolver) { 224 resolver.delete( 225 UserDictionary.Words.CONTENT_URI, DELETE_SELECTION, new String[] { word }); 226 } 227 228 private static class MyAdapter extends SimpleCursorAdapter implements SectionIndexer { 229 230 private AlphabetIndexer mIndexer; 231 232 private ViewBinder mViewBinder = new ViewBinder() { 233 234 public boolean setViewValue(View v, Cursor c, int columnIndex) { 235 if (columnIndex == INDEX_SHORTCUT) { 236 final String shortcut = c.getString(INDEX_SHORTCUT); 237 if (TextUtils.isEmpty(shortcut)) { 238 v.setVisibility(View.GONE); 239 } else { 240 ((TextView)v).setText(shortcut); 241 v.setVisibility(View.VISIBLE); 242 } 243 v.invalidate(); 244 return true; 245 } 246 247 return false; 248 } 249 }; 250 251 public MyAdapter(Context context, int layout, Cursor c, String[] from, int[] to, 252 UserDictionarySettings settings) { 253 super(context, layout, c, from, to); 254 255 if (null != c) { 256 final String alphabet = context.getString( 257 com.android.internal.R.string.fast_scroll_alphabet); 258 final int wordColIndex = c.getColumnIndexOrThrow(UserDictionary.Words.WORD); 259 mIndexer = new AlphabetIndexer(c, wordColIndex, alphabet); 260 } 261 setViewBinder(mViewBinder); 262 } 263 264 public int getPositionForSection(int section) { 265 return null == mIndexer ? 0 : mIndexer.getPositionForSection(section); 266 } 267 268 public int getSectionForPosition(int position) { 269 return null == mIndexer ? 0 : mIndexer.getSectionForPosition(position); 270 } 271 272 public Object[] getSections() { 273 return null == mIndexer ? null : mIndexer.getSections(); 274 } 275 } 276} 277