RecipientsEditor.java revision 8eed706474910ccb978acda03e85d3261037da6e
1/* 2 * Copyright (C) 2008 Esmertec AG. 3 * Copyright (C) 2008 The Android Open Source Project 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 */ 17 18package com.android.mms.ui; 19 20import com.android.mms.ui.RecipientList.Recipient; 21 22import android.content.Context; 23import android.text.Annotation; 24import android.text.Layout; 25import android.text.SpannableStringBuilder; 26import android.text.Spanned; 27import android.text.TextUtils; 28import android.text.style.TextAppearanceSpan; 29import android.util.AttributeSet; 30import android.view.KeyEvent; 31import android.view.LayoutInflater; 32import android.view.MotionEvent; 33import android.view.ContextMenu.ContextMenuInfo; 34import android.widget.ListAdapter; 35import android.widget.MultiAutoCompleteTextView; 36 37import java.util.Iterator; 38 39/** 40 * Provide UI for editing the recipients of multi-media messages. 41 */ 42public class RecipientsEditor extends MultiAutoCompleteTextView { 43 private int mLongPressedPosition = -1; 44 private final RecipientsEditorTokenizer mTokenizer; 45 46 public RecipientsEditor(Context context, AttributeSet attrs) { 47 super(context, attrs, android.R.attr.autoCompleteTextViewStyle); 48 mTokenizer = new RecipientsEditorTokenizer(context, this); 49 setTokenizer(mTokenizer); 50 } 51 52 public RecipientList getRecipientList() { 53 return mTokenizer.getRecipientList(); 54 } 55 56 public void populate(RecipientList list) { 57 SpannableStringBuilder sb = new SpannableStringBuilder(); 58 59 Iterator<Recipient> iter = list.iterator(); 60 while (iter.hasNext()) { 61 if (sb.length() != 0) { 62 sb.append(", "); 63 } 64 65 Recipient r = iter.next(); 66 sb.append(r.toToken()); 67 } 68 69 setText(sb); 70 } 71 72 private int pointToPosition(int x, int y) { 73 x -= getCompoundPaddingLeft(); 74 y -= getExtendedPaddingTop(); 75 76 x += getScrollX(); 77 y += getScrollY(); 78 79 Layout layout = getLayout(); 80 if (layout == null) { 81 return -1; 82 } 83 84 int line = layout.getLineForVertical(y); 85 int off = layout.getOffsetForHorizontal(line, x); 86 87 return off; 88 } 89 90 @Override 91 public boolean onTouchEvent(MotionEvent ev) { 92 final int action = ev.getAction(); 93 final int x = (int) ev.getX(); 94 final int y = (int) ev.getY(); 95 96 if (action == MotionEvent.ACTION_DOWN) { 97 mLongPressedPosition = pointToPosition(x, y); 98 } 99 100 return super.onTouchEvent(ev); 101 } 102 103 @Override 104 protected ContextMenuInfo getContextMenuInfo() { 105 if ((mLongPressedPosition >= 0)) { 106 Spanned text = getText(); 107 int start = mTokenizer.findTokenStart(text, mLongPressedPosition); 108 int end = mTokenizer.findTokenEnd(text, start); 109 110 if (end != start) { 111 Recipient r = getRecipientAt(getText(), start, end); 112 return new RecipientContextMenuInfo(r); 113 } 114 } 115 return null; 116 } 117 118 private static Recipient getRecipientAt(Spanned sp, int start, int end) { 119 Annotation[] a = sp.getSpans(start, end, Annotation.class); 120 String person_id = getAnnotation(a, "person_id"); 121 String name = getAnnotation(a, "name"); 122 String label = getAnnotation(a, "label"); 123 String bcc = getAnnotation(a, "bcc"); 124 125 Recipient r = new Recipient(); 126 127 r.name = name; 128 r.label = label; 129 r.bcc = bcc.equals("true"); 130 r.number = TextUtils.substring(sp, start, end); 131 132 if (person_id.length() > 0) { 133 r.person_id = Long.parseLong(person_id); 134 } else { 135 r.person_id = -1; 136 } 137 138 return r; 139 } 140 141 private static String getAnnotation(Annotation[] a, String key) { 142 for (int i = 0; i < a.length; i++) { 143 if (a[i].getKey().equals(key)) { 144 return a[i].getValue(); 145 } 146 } 147 148 return ""; 149 } 150 151 @Override 152 public boolean onKeyDown(int keyCode, KeyEvent event) { 153 if (isPopupShowing()) { 154 switch (keyCode) { 155 case KeyEvent.KEYCODE_COMMA: 156 ListAdapter adapter = getAdapter(); 157 // There is at least one item in the dropdown list 158 // when isPopupShowing() is true. 159 Object selectedItem = adapter.getItem(0); 160 replaceText(convertSelectionToString(selectedItem)); 161 dismissDropDown(); 162 return true; 163 } 164 } 165 166 return super.onKeyDown(keyCode, event); 167 } 168 169 private class RecipientsEditorTokenizer 170 extends MultiAutoCompleteTextView.CommaTokenizer 171 implements MultiAutoCompleteTextView.Tokenizer { 172 private final MultiAutoCompleteTextView mList; 173 private final LayoutInflater mInflater; 174 private final TextAppearanceSpan mLabelSpan; 175 private final TextAppearanceSpan mTypeSpan; 176 177 RecipientsEditorTokenizer(Context context, MultiAutoCompleteTextView list) { 178 mInflater = LayoutInflater.from(context); 179 mList = list; 180 181 final int size = android.R.style.TextAppearance_Small; 182 final int color = android.R.styleable.Theme_textColorSecondary; 183 mLabelSpan = new TextAppearanceSpan(context, size, color); 184 mTypeSpan = new TextAppearanceSpan(context, size, color); 185 } 186 187 public RecipientList getRecipientList() { 188 Spanned sp = mList.getText(); 189 int len = sp.length(); 190 RecipientList rl = new RecipientList(); 191 192 int start = 0; 193 int i = 0; 194 while (i < len + 1) { 195 if ((i == len) || (sp.charAt(i) == ',')) { 196 if (i > start) { 197 Recipient r = getRecipientAt(sp, start, i); 198 199 rl.add(r); 200 } 201 202 i++; 203 204 while ((i < len) && (sp.charAt(i) == ' ')) { 205 i++; 206 } 207 208 start = i; 209 } else { 210 i++; 211 } 212 } 213 214 return rl; 215 } 216 } 217 218 static class RecipientContextMenuInfo implements ContextMenuInfo { 219 final Recipient recipient; 220 221 RecipientContextMenuInfo(Recipient r) { 222 recipient = r; 223 } 224 } 225} 226