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 17 package com.android.settings; 18 19 import android.app.AlertDialog; 20 import android.app.Dialog; 21 import android.app.ListActivity; 22 import android.content.Context; 23 import android.content.DialogInterface; 24 import android.database.Cursor; 25 import android.os.Bundle; 26 import android.provider.UserDictionary; 27 import android.text.InputType; 28 import android.view.ContextMenu; 29 import android.view.Menu; 30 import android.view.MenuItem; 31 import android.view.View; 32 import android.view.ContextMenu.ContextMenuInfo; 33 import android.widget.AlphabetIndexer; 34 import android.widget.EditText; 35 import android.widget.ListAdapter; 36 import android.widget.ListView; 37 import android.widget.SectionIndexer; 38 import android.widget.SimpleCursorAdapter; 39 import android.widget.TextView; 40 import android.widget.AdapterView.AdapterContextMenuInfo; 41 42 import java.util.Locale; 43 44 public class UserDictionarySettings extends ListActivity { 45 46 private static final String INSTANCE_KEY_DIALOG_EDITING_WORD = "DIALOG_EDITING_WORD"; 47 private static final String INSTANCE_KEY_ADDED_WORD = "DIALOG_ADDED_WORD"; 48 49 private static final String[] QUERY_PROJECTION = { 50 UserDictionary.Words._ID, UserDictionary.Words.WORD 51 }; 52 53 // Either the locale is empty (means the word is applicable to all locales) 54 // or the word equals our current locale 55 private static final String QUERY_SELECTION = UserDictionary.Words.LOCALE + "=? OR " 56 + UserDictionary.Words.LOCALE + " is null"; 57 58 private static final String DELETE_SELECTION = UserDictionary.Words.WORD + "=?"; 59 60 private static final String EXTRA_WORD = "word"; 61 62 private static final int CONTEXT_MENU_EDIT = Menu.FIRST; 63 private static final int CONTEXT_MENU_DELETE = Menu.FIRST + 1; 64 65 private static final int OPTIONS_MENU_ADD = Menu.FIRST; 66 67 private static final int DIALOG_ADD_OR_EDIT = 0; 68 69 /** The word being edited in the dialog (null means the user is adding a word). */ 70 private String mDialogEditingWord; 71 72 private Cursor mCursor; 73 74 private boolean mAddedWordAlready; 75 private boolean mAutoReturn; 76 77 @Override onCreate(Bundle savedInstanceState)78 protected void onCreate(Bundle savedInstanceState) { 79 super.onCreate(savedInstanceState); 80 81 setContentView(R.layout.list_content_with_empty_view); 82 83 mCursor = createCursor(); 84 setListAdapter(createAdapter()); 85 86 TextView emptyView = (TextView) findViewById(R.id.empty); 87 emptyView.setText(R.string.user_dict_settings_empty_text); 88 89 ListView listView = getListView(); 90 listView.setFastScrollEnabled(true); 91 listView.setEmptyView(emptyView); 92 93 registerForContextMenu(listView); 94 } 95 96 @Override onResume()97 protected void onResume() { 98 super.onResume(); 99 if (!mAddedWordAlready 100 && getIntent().getAction().equals("com.android.settings.USER_DICTIONARY_INSERT")) { 101 String word = getIntent().getStringExtra(EXTRA_WORD); 102 mAutoReturn = true; 103 if (word != null) { 104 showAddOrEditDialog(word); 105 } 106 } 107 } 108 @Override onRestoreInstanceState(Bundle state)109 protected void onRestoreInstanceState(Bundle state) { 110 super.onRestoreInstanceState(state); 111 mDialogEditingWord = state.getString(INSTANCE_KEY_DIALOG_EDITING_WORD); 112 mAddedWordAlready = state.getBoolean(INSTANCE_KEY_ADDED_WORD, false); 113 } 114 115 @Override onSaveInstanceState(Bundle outState)116 protected void onSaveInstanceState(Bundle outState) { 117 super.onSaveInstanceState(outState); 118 outState.putString(INSTANCE_KEY_DIALOG_EDITING_WORD, mDialogEditingWord); 119 outState.putBoolean(INSTANCE_KEY_ADDED_WORD, mAddedWordAlready); 120 } 121 createCursor()122 private Cursor createCursor() { 123 String currentLocale = Locale.getDefault().toString(); 124 // Case-insensitive sort 125 return managedQuery(UserDictionary.Words.CONTENT_URI, QUERY_PROJECTION, 126 QUERY_SELECTION, new String[] { currentLocale }, 127 "UPPER(" + UserDictionary.Words.WORD + ")"); 128 } 129 createAdapter()130 private ListAdapter createAdapter() { 131 return new MyAdapter(this, 132 android.R.layout.simple_list_item_1, mCursor, 133 new String[] { UserDictionary.Words.WORD }, 134 new int[] { android.R.id.text1 }); 135 } 136 137 @Override onListItemClick(ListView l, View v, int position, long id)138 protected void onListItemClick(ListView l, View v, int position, long id) { 139 openContextMenu(v); 140 } 141 142 @Override onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo)143 public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) { 144 if (!(menuInfo instanceof AdapterContextMenuInfo)) return; 145 146 AdapterContextMenuInfo adapterMenuInfo = (AdapterContextMenuInfo) menuInfo; 147 menu.setHeaderTitle(getWord(adapterMenuInfo.position)); 148 menu.add(0, CONTEXT_MENU_EDIT, 0, 149 R.string.user_dict_settings_context_menu_edit_title); 150 menu.add(0, CONTEXT_MENU_DELETE, 0, 151 R.string.user_dict_settings_context_menu_delete_title); 152 } 153 154 @Override onContextItemSelected(MenuItem item)155 public boolean onContextItemSelected(MenuItem item) { 156 ContextMenuInfo menuInfo = item.getMenuInfo(); 157 if (!(menuInfo instanceof AdapterContextMenuInfo)) return false; 158 159 AdapterContextMenuInfo adapterMenuInfo = (AdapterContextMenuInfo) menuInfo; 160 String word = getWord(adapterMenuInfo.position); 161 162 switch (item.getItemId()) { 163 case CONTEXT_MENU_DELETE: 164 deleteWord(word); 165 return true; 166 167 case CONTEXT_MENU_EDIT: 168 showAddOrEditDialog(word); 169 return true; 170 } 171 172 return false; 173 } 174 175 @Override onCreateOptionsMenu(Menu menu)176 public boolean onCreateOptionsMenu(Menu menu) { 177 menu.add(0, OPTIONS_MENU_ADD, 0, R.string.user_dict_settings_add_menu_title) 178 .setIcon(R.drawable.ic_menu_add); 179 return true; 180 } 181 182 @Override onOptionsItemSelected(MenuItem item)183 public boolean onOptionsItemSelected(MenuItem item) { 184 showAddOrEditDialog(null); 185 return true; 186 } 187 showAddOrEditDialog(String editingWord)188 private void showAddOrEditDialog(String editingWord) { 189 mDialogEditingWord = editingWord; 190 showDialog(DIALOG_ADD_OR_EDIT); 191 } 192 getWord(int position)193 private String getWord(int position) { 194 mCursor.moveToPosition(position); 195 return mCursor.getString( 196 mCursor.getColumnIndexOrThrow(UserDictionary.Words.WORD)); 197 } 198 199 @Override onCreateDialog(int id)200 protected Dialog onCreateDialog(int id) { 201 View content = getLayoutInflater().inflate(R.layout.dialog_edittext, null); 202 final EditText editText = (EditText) content.findViewById(R.id.edittext); 203 // No prediction in soft keyboard mode. TODO: Create a better way to disable prediction 204 editText.setInputType(InputType.TYPE_CLASS_TEXT 205 | InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE); 206 207 return new AlertDialog.Builder(this) 208 .setTitle(mDialogEditingWord != null 209 ? R.string.user_dict_settings_edit_dialog_title 210 : R.string.user_dict_settings_add_dialog_title) 211 .setView(content) 212 .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { 213 public void onClick(DialogInterface dialog, int which) { 214 onAddOrEditFinished(editText.getText().toString()); 215 if (mAutoReturn) finish(); 216 }}) 217 .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { 218 public void onClick(DialogInterface dialog, int which) { 219 if (mAutoReturn) finish(); 220 }}) 221 .create(); 222 } 223 @Override 224 protected void onPrepareDialog(int id, Dialog d) { 225 AlertDialog dialog = (AlertDialog) d; 226 d.setTitle(mDialogEditingWord != null 227 ? R.string.user_dict_settings_edit_dialog_title 228 : R.string.user_dict_settings_add_dialog_title); 229 EditText editText = (EditText) dialog.findViewById(R.id.edittext); 230 editText.setText(mDialogEditingWord); 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(this, word.toString(), 244 250, UserDictionary.Words.LOCALE_TYPE_ALL); 245 mCursor.requery(); 246 mAddedWordAlready = true; 247 } 248 249 private void deleteWord(String word) { 250 getContentResolver().delete(UserDictionary.Words.CONTENT_URI, DELETE_SELECTION, 251 new String[] { word }); 252 } 253 254 private static class MyAdapter extends SimpleCursorAdapter implements SectionIndexer { 255 private AlphabetIndexer mIndexer; 256 257 public MyAdapter(Context context, int layout, Cursor c, String[] from, int[] to) { 258 super(context, layout, c, from, to); 259 260 int wordColIndex = c.getColumnIndexOrThrow(UserDictionary.Words.WORD); 261 String alphabet = context.getString(com.android.internal.R.string.fast_scroll_alphabet); 262 mIndexer = new AlphabetIndexer(c, wordColIndex, alphabet); 263 } 264 265 public int getPositionForSection(int section) { 266 return mIndexer.getPositionForSection(section); 267 } 268 269 public int getSectionForPosition(int position) { 270 return mIndexer.getSectionForPosition(position); 271 } 272 273 public Object[] getSections() { 274 return mIndexer.getSections(); 275 } 276 } 277 } 278