UserDictionarySettings.java revision e98256646c0c1a8d79af5d23bf5330daafb5cf14
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.Context; 24import android.content.DialogInterface; 25import android.content.Intent; 26import android.database.Cursor; 27import android.os.Bundle; 28import android.provider.UserDictionary; 29import android.text.InputType; 30import android.util.Log; 31import android.view.LayoutInflater; 32import android.view.Menu; 33import android.view.MenuInflater; 34import android.view.MenuItem; 35import android.view.View; 36import android.view.ViewGroup; 37import android.view.WindowManager; 38import android.widget.AlphabetIndexer; 39import android.widget.EditText; 40import android.widget.ImageView; 41import android.widget.ListAdapter; 42import android.widget.ListView; 43import android.widget.SectionIndexer; 44import android.widget.SimpleCursorAdapter; 45import android.widget.TextView; 46 47import com.android.settings.SettingsPreferenceFragment.SettingsDialogFragment; 48 49import java.util.Locale; 50 51public class UserDictionarySettings extends ListFragment implements DialogCreatable { 52 private static final String TAG = "UserDictionarySettings"; 53 54 private static final String INSTANCE_KEY_DIALOG_EDITING_WORD = "DIALOG_EDITING_WORD"; 55 private static final String INSTANCE_KEY_ADDED_WORD = "DIALOG_ADDED_WORD"; 56 57 private static final String[] QUERY_PROJECTION = { 58 UserDictionary.Words._ID, UserDictionary.Words.WORD 59 }; 60 61 private static final int INDEX_ID = 0; 62 private static final int INDEX_WORD = 1; 63 64 // Either the locale is empty (means the word is applicable to all locales) 65 // or the word equals our current locale 66 private static final String QUERY_SELECTION = UserDictionary.Words.LOCALE + "=? OR " 67 + UserDictionary.Words.LOCALE + " is null"; 68 69 private static final String DELETE_SELECTION = UserDictionary.Words.WORD + "=?"; 70 71 private static final String EXTRA_WORD = "word"; 72 73 private static final int OPTIONS_MENU_ADD = Menu.FIRST; 74 75 private static final int DIALOG_ADD_OR_EDIT = 0; 76 77 /** The word being edited in the dialog (null means the user is adding a word). */ 78 private String mDialogEditingWord; 79 80 private View mView; 81 private Cursor mCursor; 82 83 private boolean mAddedWordAlready; 84 private boolean mAutoReturn; 85 86 private SettingsDialogFragment mDialogFragment; 87 88 @Override 89 public void onCreate(Bundle savedInstanceState) { 90 super.onCreate(savedInstanceState); 91 } 92 93 @Override 94 public View onCreateView(LayoutInflater inflater, ViewGroup container, 95 Bundle savedInstanceState) { 96 mView = inflater.inflate(R.layout.list_content_with_empty_view, container, false); 97 return mView; 98 } 99 100 @Override 101 public void onActivityCreated(Bundle savedInstanceState) { 102 super.onActivityCreated(savedInstanceState); 103 104 mCursor = createCursor(); 105 TextView emptyView = (TextView)mView.findViewById(R.id.empty); 106 emptyView.setText(R.string.user_dict_settings_empty_text); 107 108 final ListView listView = getListView(); 109 listView.setAdapter(createAdapter()); 110 listView.setFastScrollEnabled(true); 111 listView.setEmptyView(emptyView); 112 113 setHasOptionsMenu(true); 114 115 if (savedInstanceState != null) { 116 mDialogEditingWord = savedInstanceState.getString(INSTANCE_KEY_DIALOG_EDITING_WORD); 117 mAddedWordAlready = savedInstanceState.getBoolean(INSTANCE_KEY_ADDED_WORD, false); 118 } 119 } 120 121 @Override 122 public void onResume() { 123 super.onResume(); 124 final Intent intent = getActivity().getIntent(); 125 if (!mAddedWordAlready 126 && intent.getAction().equals("com.android.settings.USER_DICTIONARY_INSERT")) { 127 final String word = intent.getStringExtra(EXTRA_WORD); 128 mAutoReturn = true; 129 if (word != null) { 130 showAddOrEditDialog(word); 131 } 132 } 133 } 134 135 @Override 136 public void onSaveInstanceState(Bundle outState) { 137 super.onSaveInstanceState(outState); 138 outState.putString(INSTANCE_KEY_DIALOG_EDITING_WORD, mDialogEditingWord); 139 outState.putBoolean(INSTANCE_KEY_ADDED_WORD, mAddedWordAlready); 140 } 141 142 private Cursor createCursor() { 143 String currentLocale = Locale.getDefault().toString(); 144 // Case-insensitive sort 145 return getActivity().managedQuery(UserDictionary.Words.CONTENT_URI, QUERY_PROJECTION, 146 QUERY_SELECTION, new String[] { currentLocale }, 147 "UPPER(" + UserDictionary.Words.WORD + ")"); 148 } 149 150 private ListAdapter createAdapter() { 151 return new MyAdapter(getActivity(), 152 R.layout.user_dictionary_item, mCursor, 153 new String[] { UserDictionary.Words.WORD, UserDictionary.Words._ID }, 154 new int[] { android.R.id.text1, R.id.delete_button }, this); 155 } 156 157 @Override 158 public void onListItemClick(ListView l, View v, int position, long id) { 159 String word = getWord(position); 160 if (word != null) { 161 showAddOrEditDialog(word); 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 } 172 173 @Override 174 public boolean onOptionsItemSelected(MenuItem item) { 175 showAddOrEditDialog(null); 176 return true; 177 } 178 179 private void showAddOrEditDialog(String editingWord) { 180 mDialogEditingWord = editingWord; 181 showDialog(DIALOG_ADD_OR_EDIT); 182 } 183 184 private String getWord(int position) { 185 mCursor.moveToPosition(position); 186 // Handle a possible race-condition 187 if (mCursor.isAfterLast()) return null; 188 189 return mCursor.getString( 190 mCursor.getColumnIndexOrThrow(UserDictionary.Words.WORD)); 191 } 192 193 @Override 194 public Dialog onCreateDialog(int id) { 195 final Activity activity = getActivity(); 196 final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(activity); 197 final LayoutInflater inflater = LayoutInflater.from(dialogBuilder.getContext()); 198 final View content = inflater.inflate(R.layout.dialog_edittext, null); 199 final EditText editText = (EditText) content.findViewById(R.id.edittext); 200 editText.setText(mDialogEditingWord); 201 // No prediction in soft keyboard mode. TODO: Create a better way to disable prediction 202 editText.setInputType(InputType.TYPE_CLASS_TEXT 203 | InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE); 204 205 AlertDialog dialog = dialogBuilder 206 .setTitle(mDialogEditingWord != null 207 ? R.string.user_dict_settings_edit_dialog_title 208 : R.string.user_dict_settings_add_dialog_title) 209 .setView(content) 210 .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { 211 public void onClick(DialogInterface dialog, int which) { 212 onAddOrEditFinished(editText.getText().toString()); 213 if (mAutoReturn) activity.onBackPressed(); 214 }}) 215 .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { 216 public void onClick(DialogInterface dialog, int which) { 217 if (mAutoReturn) activity.onBackPressed(); 218 }}) 219 .create(); 220 dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE | 221 WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE); 222 return dialog; 223 } 224 225 private void showDialog(int dialogId) { 226 if (mDialogFragment != null) { 227 Log.e(TAG, "Old dialog fragment not null!"); 228 } 229 mDialogFragment = new SettingsDialogFragment(this, dialogId); 230 mDialogFragment.show(getActivity().getFragmentManager(), Integer.toString(dialogId)); 231 } 232 233 private void onAddOrEditFinished(String word) { 234 if (mDialogEditingWord != null) { 235 // The user was editing a word, so do a delete/add 236 deleteWord(mDialogEditingWord); 237 } 238 239 // Disallow duplicates 240 deleteWord(word); 241 242 // TODO: present UI for picking whether to add word to all locales, or current. 243 UserDictionary.Words.addWord(getActivity(), word.toString(), 244 250, UserDictionary.Words.LOCALE_TYPE_ALL); 245 if (!mCursor.requery()) { 246 throw new IllegalStateException("can't requery on already-closed cursor."); 247 } 248 mAddedWordAlready = true; 249 } 250 251 private void deleteWord(String word) { 252 getActivity().getContentResolver().delete( 253 UserDictionary.Words.CONTENT_URI, DELETE_SELECTION, new String[] { word }); 254 } 255 256 private static class MyAdapter extends SimpleCursorAdapter implements SectionIndexer, 257 View.OnClickListener { 258 259 private AlphabetIndexer mIndexer; 260 private UserDictionarySettings mSettings; 261 262 private ViewBinder mViewBinder = new ViewBinder() { 263 264 public boolean setViewValue(View v, Cursor c, int columnIndex) { 265 if (v instanceof ImageView && columnIndex == INDEX_ID) { 266 v.setOnClickListener(MyAdapter.this); 267 v.setTag(c.getString(INDEX_WORD)); 268 return true; 269 } 270 271 return false; 272 } 273 }; 274 275 public MyAdapter(Context context, int layout, Cursor c, String[] from, int[] to, 276 UserDictionarySettings settings) { 277 super(context, layout, c, from, to); 278 279 mSettings = settings; 280 int wordColIndex = c.getColumnIndexOrThrow(UserDictionary.Words.WORD); 281 String alphabet = context.getString( 282 com.android.internal.R.string.fast_scroll_alphabet); 283 mIndexer = new AlphabetIndexer(c, wordColIndex, alphabet); 284 setViewBinder(mViewBinder); 285 } 286 287 public int getPositionForSection(int section) { 288 return mIndexer.getPositionForSection(section); 289 } 290 291 public int getSectionForPosition(int position) { 292 return mIndexer.getSectionForPosition(position); 293 } 294 295 public Object[] getSections() { 296 return mIndexer.getSections(); 297 } 298 299 public void onClick(View v) { 300 mSettings.deleteWord((String) v.getTag()); 301 } 302 } 303} 304