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