MessageListItem.java revision 8429b927ffb65c52b00da410fd60b2b1790c1026
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 java.util.Map;
21import java.util.regex.Matcher;
22import java.util.regex.Pattern;
23
24import android.app.AlertDialog;
25import android.content.Context;
26import android.content.DialogInterface;
27import android.content.Intent;
28import android.content.res.Resources;
29import android.graphics.Bitmap;
30import android.graphics.BitmapFactory;
31import android.graphics.Typeface;
32import android.graphics.Paint.FontMetricsInt;
33import android.graphics.drawable.Drawable;
34import android.net.Uri;
35import android.os.Handler;
36import android.os.Message;
37import android.provider.Browser;
38import android.provider.Telephony.Mms;
39import android.provider.Telephony.Sms;
40import android.telephony.PhoneNumberUtils;
41import android.text.Html;
42import android.text.Spannable;
43import android.text.SpannableStringBuilder;
44import android.text.TextUtils;
45import android.text.method.HideReturnsTransformationMethod;
46import android.text.style.ForegroundColorSpan;
47import android.text.style.LineHeightSpan;
48import android.text.style.StyleSpan;
49import android.text.style.TextAppearanceSpan;
50import android.text.style.URLSpan;
51import android.util.AttributeSet;
52import android.util.DisplayMetrics;
53import android.util.Log;
54import android.view.Gravity;
55import android.view.View;
56import android.view.ViewGroup;
57import android.view.View.OnClickListener;
58import android.widget.ArrayAdapter;
59import android.widget.Button;
60import android.widget.ImageButton;
61import android.widget.ImageView;
62import android.widget.LinearLayout;
63import android.widget.QuickContactBadge;
64import android.widget.RelativeLayout;
65import android.widget.TextView;
66
67import com.android.mms.MmsApp;
68import com.android.mms.R;
69import com.android.mms.data.WorkingMessage;
70import com.android.mms.transaction.Transaction;
71import com.android.mms.transaction.TransactionBundle;
72import com.android.mms.transaction.TransactionService;
73import com.android.mms.util.DownloadManager;
74import com.android.mms.util.SmileyParser;
75import com.google.android.mms.ContentType;
76import com.google.android.mms.pdu.PduHeaders;
77
78/**
79 * This class provides view of a message in the messages list.
80 */
81public class MessageListItem extends LinearLayout implements
82        SlideViewInterface, OnClickListener {
83    public static final String EXTRA_URLS = "com.android.mms.ExtraUrls";
84
85    private static final String TAG = "MessageListItem";
86    private static final StyleSpan STYLE_BOLD = new StyleSpan(Typeface.BOLD);
87
88    static final int MSG_LIST_EDIT_MMS   = 1;
89    static final int MSG_LIST_EDIT_SMS   = 2;
90
91    private View mMsgListItem;
92    private View mMmsView;
93    private ImageView mImageView;
94    private ImageView mLockedIndicator;
95    private ImageView mDeliveredIndicator;
96    private ImageView mDetailsIndicator;
97    private ImageButton mSlideShowButton;
98    private TextView mBodyTextView;
99    private Button mDownloadButton;
100    private TextView mDownloadingLabel;
101    private QuickContactBadge mAvatar;
102    private Handler mHandler;
103    private MessageItem mMessageItem;
104    private String mDefaultCountryIso;
105    private TextView mDateView;
106    private LinearLayout mStatusIcons;
107    private Drawable mLeftDivitDrawable;
108    private Drawable mRightDivitDrawable;
109    private View mDivit;        // little triangle on the side of the avatar
110
111    public MessageListItem(Context context) {
112        super(context);
113        mDefaultCountryIso = MmsApp.getApplication().getCurrentCountryIso();
114    }
115
116    public MessageListItem(Context context, AttributeSet attrs) {
117        super(context, attrs);
118
119        int color = mContext.getResources().getColor(R.color.timestamp_color);
120        mColorSpan = new ForegroundColorSpan(color);
121        mDefaultCountryIso = MmsApp.getApplication().getCurrentCountryIso();
122    }
123
124    @Override
125    protected void onFinishInflate() {
126        super.onFinishInflate();
127
128        mMsgListItem = findViewById(R.id.msg_list_item);
129        mBodyTextView = (TextView) findViewById(R.id.text_view);
130        mDateView = (TextView) findViewById(R.id.date_view);
131        mLockedIndicator = (ImageView) findViewById(R.id.locked_indicator);
132        mDeliveredIndicator = (ImageView) findViewById(R.id.delivered_indicator);
133        mDetailsIndicator = (ImageView) findViewById(R.id.details_indicator);
134        mAvatar = (QuickContactBadge) findViewById(R.id.avatar);
135        mStatusIcons = (LinearLayout) findViewById(R.id.status_icons);
136
137        mDivit = findViewById(R.id.divit);
138        float density = mContext.getResources().getDisplayMetrics().density;
139        mLeftDivitDrawable = new DivitDrawable(DivitDrawable.LEFT_UPPER, density);
140        mRightDivitDrawable = new DivitDrawable(DivitDrawable.RIGHT_UPPER, density);
141    }
142
143    public void bind(MessageListAdapter.AvatarCache avatarCache, MessageItem msgItem) {
144        mMessageItem = msgItem;
145
146        setLongClickable(false);
147
148        switch (msgItem.mMessageType) {
149            case PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND:
150                bindNotifInd(msgItem);
151                break;
152            default:
153                bindCommonMessage(avatarCache, msgItem);
154                break;
155        }
156    }
157
158    public MessageItem getMessageItem() {
159        return mMessageItem;
160    }
161
162    public void setMsgListItemHandler(Handler handler) {
163        mHandler = handler;
164    }
165
166    private void bindNotifInd(final MessageItem msgItem) {
167        hideMmsViewIfNeeded();
168
169        String msgSizeText = mContext.getString(R.string.message_size_label)
170                                + String.valueOf((msgItem.mMessageSize + 1023) / 1024)
171                                + mContext.getString(R.string.kilobyte);
172
173        mBodyTextView.setText(formatMessage(msgItem, msgItem.mContact, null, msgItem.mSubject,
174                                            msgItem.mHighlight, msgItem.mTextContentType));
175
176        mDateView.setText(msgSizeText + " " + msgItem.mTimestamp);
177
178        int state = DownloadManager.getInstance().getState(msgItem.mMessageUri);
179        switch (state) {
180            case DownloadManager.STATE_DOWNLOADING:
181                inflateDownloadControls();
182                mDownloadingLabel.setVisibility(View.VISIBLE);
183                mDownloadButton.setVisibility(View.GONE);
184                break;
185            case DownloadManager.STATE_UNSTARTED:
186            case DownloadManager.STATE_TRANSIENT_FAILURE:
187            case DownloadManager.STATE_PERMANENT_FAILURE:
188            default:
189                setLongClickable(true);
190                inflateDownloadControls();
191                mDownloadingLabel.setVisibility(View.GONE);
192                mDownloadButton.setVisibility(View.VISIBLE);
193                mDownloadButton.setOnClickListener(new OnClickListener() {
194                    public void onClick(View v) {
195                        mDownloadingLabel.setVisibility(View.VISIBLE);
196                        mDownloadButton.setVisibility(View.GONE);
197                        Intent intent = new Intent(mContext, TransactionService.class);
198                        intent.putExtra(TransactionBundle.URI, msgItem.mMessageUri.toString());
199                        intent.putExtra(TransactionBundle.TRANSACTION_TYPE,
200                                Transaction.RETRIEVE_TRANSACTION);
201                        mContext.startService(intent);
202                    }
203                });
204                break;
205        }
206
207        // Hide the indicators.
208        mLockedIndicator.setVisibility(View.GONE);
209        mDeliveredIndicator.setVisibility(View.GONE);
210        mDetailsIndicator.setVisibility(View.GONE);
211    }
212
213    private void bindCommonMessage(final MessageListAdapter.AvatarCache avatarCache,
214            final MessageItem msgItem) {
215        if (mDownloadButton != null) {
216            mDownloadButton.setVisibility(View.GONE);
217            mDownloadingLabel.setVisibility(View.GONE);
218        }
219        // Since the message text should be concatenated with the sender's
220        // address(or name), I have to display it here instead of
221        // displaying it by the Presenter.
222        mBodyTextView.setTransformationMethod(HideReturnsTransformationMethod.getInstance());
223
224        String addr = null;
225        if (!Sms.isOutgoingFolder(msgItem.mBoxId)) {
226            addr = msgItem.mAddress;
227        } else {
228            addr = MmsApp.getApplication().getTelephonyManager().getLine1Number();
229        }
230        if (!TextUtils.isEmpty(addr)) {
231            MessageListAdapter.AvatarCache.ContactData contactData = avatarCache.get(addr);
232            mAvatar.setImageDrawable(contactData.getAvatar());
233            Uri contactUri = contactData.getContactUri();
234            // Since we load the contact info in the background, on the first screenfull of
235            // messages, it's likely we haven't loaded the contact URI info yet. In that case,
236            // fall back and use the phone number.
237            if (contactUri != null) {
238                mAvatar.assignContactUri(contactUri);
239            } else {
240                mAvatar.assignContactFromPhone(addr, true);
241            }
242        } else {
243            mAvatar.setImageToDefault();
244            mAvatar.assignContactUri(null);
245        }
246
247        // Get and/or lazily set the formatted message from/on the
248        // MessageItem.  Because the MessageItem instances come from a
249        // cache (currently of size ~50), the hit rate on avoiding the
250        // expensive formatMessage() call is very high.
251        CharSequence formattedMessage = msgItem.getCachedFormattedMessage();
252        if (formattedMessage == null) {
253            formattedMessage = formatMessage(msgItem, msgItem.mContact, msgItem.mBody,
254                                             msgItem.mSubject,
255                                             msgItem.mHighlight, msgItem.mTextContentType);
256        }
257        mBodyTextView.setText(formattedMessage);
258
259        // If we're in the process of sending a message (i.e. pending), then we show a "SENDING..."
260        // string in place of the timestamp.
261        mDateView.setText(msgItem.isSending() ?
262                mContext.getResources().getString(R.string.sending_message) :
263                    msgItem.mTimestamp);
264
265        if (msgItem.isSms()) {
266            hideMmsViewIfNeeded();
267        } else {
268            Presenter presenter = PresenterFactory.getPresenter(
269                    "MmsThumbnailPresenter", mContext,
270                    this, msgItem.mSlideshow);
271            presenter.present();
272
273            if (msgItem.mAttachmentType != WorkingMessage.TEXT) {
274                inflateMmsView();
275                mMmsView.setVisibility(View.VISIBLE);
276                setOnClickListener(msgItem);
277                drawPlaybackButton(msgItem);
278            } else {
279                hideMmsViewIfNeeded();
280            }
281        }
282
283        adjustLayoutItems(msgItem);
284        drawRightStatusIndicator(msgItem);
285
286        requestLayout();
287    }
288
289    private void adjustLayoutItems(final MessageItem msgItem) {
290        // Put the avatar on the left or right
291        RelativeLayout.LayoutParams avatarLayout =
292            (RelativeLayout.LayoutParams)mAvatar.getLayoutParams();
293        RelativeLayout.LayoutParams textLayout =
294            (RelativeLayout.LayoutParams)mBodyTextView.getLayoutParams();
295        RelativeLayout.LayoutParams dateLayout =
296            (RelativeLayout.LayoutParams)mDateView.getLayoutParams();
297        RelativeLayout.LayoutParams statusIconsLayout =
298            (RelativeLayout.LayoutParams)mStatusIcons.getLayoutParams();
299        RelativeLayout.LayoutParams divitLayout =
300            (RelativeLayout.LayoutParams)mDivit.getLayoutParams();
301
302        Resources resources = mContext.getResources();
303        int textPaddingLeftRight = resources.getDimensionPixelOffset(
304                R.dimen.message_item_text_padding_left_right);
305        int textPaddingTop = resources.getDimensionPixelOffset(
306                R.dimen.message_item_text_padding_top);
307
308        if (msgItem.mBoxId == Mms.MESSAGE_BOX_INBOX) {
309            // Avatar on left, text adjusted left
310            // undo the old rules first
311            textLayout.addRule(RelativeLayout.ALIGN_PARENT_LEFT, 0);
312            textLayout.addRule(RelativeLayout.LEFT_OF, 0);
313            avatarLayout.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, 0);
314            statusIconsLayout.addRule(RelativeLayout.LEFT_OF, 0);
315            dateLayout.addRule(RelativeLayout.LEFT_OF, 0);
316            divitLayout.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, 0);
317
318            // set the new rules
319            avatarLayout.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
320            textLayout.addRule(RelativeLayout.RIGHT_OF, R.id.avatar);
321            textLayout.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
322            dateLayout.addRule(RelativeLayout.RIGHT_OF, R.id.avatar);
323            statusIconsLayout.addRule(RelativeLayout.RIGHT_OF, R.id.date_view);
324
325            mBodyTextView.setPadding(textPaddingLeftRight,
326                    textPaddingTop,
327                    textPaddingLeftRight,
328                    0);
329            mBodyTextView.setGravity(Gravity.LEFT);
330            mDateView.setPadding(textPaddingLeftRight, 0, 0, 0);
331
332            mDivit.setBackgroundDrawable(mRightDivitDrawable);
333            divitLayout.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
334        } else {
335            // Avatar on right, text adjusted right
336            // undo the old rules first
337            avatarLayout.addRule(RelativeLayout.ALIGN_PARENT_LEFT, 0);
338            textLayout.addRule(RelativeLayout.RIGHT_OF, 0);
339            textLayout.addRule(RelativeLayout.ALIGN_PARENT_RIGHT, 0);
340            dateLayout.addRule(RelativeLayout.RIGHT_OF, 0);
341            statusIconsLayout.addRule(RelativeLayout.RIGHT_OF, 0);
342            divitLayout.addRule(RelativeLayout.ALIGN_PARENT_LEFT, 0);
343
344            // set the new rules
345            textLayout.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
346            textLayout.addRule(RelativeLayout.LEFT_OF, R.id.avatar);
347            avatarLayout.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
348            statusIconsLayout.addRule(RelativeLayout.LEFT_OF, R.id.date_view);
349            dateLayout.addRule(RelativeLayout.LEFT_OF, R.id.avatar);
350
351            mBodyTextView.setPadding(resources
352                    .getDimensionPixelOffset(R.dimen.message_item_avatar_on_right_text_indent),
353                        textPaddingTop,
354                        textPaddingLeftRight,
355                        0);
356            mBodyTextView.setGravity(Gravity.RIGHT);
357            mDateView.setPadding(0, 0, textPaddingLeftRight, 0);
358
359            mDivit.setBackgroundDrawable(mLeftDivitDrawable);
360            divitLayout.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
361        }
362    }
363
364    private void hideMmsViewIfNeeded() {
365        if (mMmsView != null) {
366            mMmsView.setVisibility(View.GONE);
367        }
368    }
369
370    public void startAudio() {
371        // TODO Auto-generated method stub
372    }
373
374    public void startVideo() {
375        // TODO Auto-generated method stub
376    }
377
378    public void setAudio(Uri audio, String name, Map<String, ?> extras) {
379        // TODO Auto-generated method stub
380    }
381
382    public void setImage(String name, Bitmap bitmap) {
383        inflateMmsView();
384
385        try {
386            if (null == bitmap) {
387                bitmap = BitmapFactory.decodeResource(getResources(),
388                        R.drawable.ic_missing_thumbnail_picture);
389            }
390            mImageView.setImageBitmap(bitmap);
391            mImageView.setVisibility(VISIBLE);
392        } catch (java.lang.OutOfMemoryError e) {
393            Log.e(TAG, "setImage: out of memory: ", e);
394        }
395    }
396
397    private void inflateMmsView() {
398        if (mMmsView == null) {
399            //inflate the surrounding view_stub
400            findViewById(R.id.mms_layout_view_stub).setVisibility(VISIBLE);
401
402            mMmsView = findViewById(R.id.mms_view);
403            mImageView = (ImageView) findViewById(R.id.image_view);
404            mSlideShowButton = (ImageButton) findViewById(R.id.play_slideshow_button);
405        }
406    }
407
408    private void inflateDownloadControls() {
409        if (mDownloadButton == null) {
410            //inflate the download controls
411            findViewById(R.id.mms_downloading_view_stub).setVisibility(VISIBLE);
412            mDownloadButton = (Button) findViewById(R.id.btn_download_msg);
413            mDownloadingLabel = (TextView) findViewById(R.id.label_downloading);
414        }
415    }
416
417
418    private LineHeightSpan mSpan = new LineHeightSpan() {
419        public void chooseHeight(CharSequence text, int start,
420                int end, int spanstartv, int v, FontMetricsInt fm) {
421            fm.ascent -= 10;
422        }
423    };
424
425    TextAppearanceSpan mTextSmallSpan =
426        new TextAppearanceSpan(mContext, android.R.style.TextAppearance_Small);
427
428    ForegroundColorSpan mColorSpan = null;  // set in ctor
429
430    private CharSequence formatMessage(MessageItem msgItem, String contact, String body,
431                                       String subject, Pattern highlight,
432                                       String contentType) {
433        SpannableStringBuilder buf = new SpannableStringBuilder();
434
435        boolean hasSubject = !TextUtils.isEmpty(subject);
436        if (hasSubject) {
437            buf.append(mContext.getResources().getString(R.string.inline_subject, subject));
438        }
439
440        if (!TextUtils.isEmpty(body)) {
441            // Converts html to spannable if ContentType is "text/html".
442            if (contentType != null && ContentType.TEXT_HTML.equals(contentType)) {
443                buf.append("\n");
444                buf.append(Html.fromHtml(body));
445            } else {
446                if (hasSubject) {
447                    buf.append(" - ");
448                }
449                SmileyParser parser = SmileyParser.getInstance();
450                buf.append(parser.addSmileySpans(body));
451            }
452        }
453
454        if (highlight != null) {
455            Matcher m = highlight.matcher(buf.toString());
456            while (m.find()) {
457                buf.setSpan(new StyleSpan(Typeface.BOLD), m.start(), m.end(), 0);
458            }
459        }
460        return buf;
461    }
462
463    private void drawPlaybackButton(MessageItem msgItem) {
464        switch (msgItem.mAttachmentType) {
465            case WorkingMessage.SLIDESHOW:
466            case WorkingMessage.AUDIO:
467            case WorkingMessage.VIDEO:
468                // Show the 'Play' button and bind message info on it.
469                mSlideShowButton.setTag(msgItem);
470                // Set call-back for the 'Play' button.
471                mSlideShowButton.setOnClickListener(this);
472                mSlideShowButton.setVisibility(View.VISIBLE);
473                setLongClickable(true);
474
475                // When we show the mSlideShowButton, this list item's onItemClickListener doesn't
476                // get called. (It gets set in ComposeMessageActivity:
477                // mMsgListView.setOnItemClickListener) Here we explicitly set the item's
478                // onClickListener. It allows the item to respond to embedded html links and at the
479                // same time, allows the slide show play button to work.
480                setOnClickListener(new OnClickListener() {
481                    public void onClick(View v) {
482                        onMessageListItemClick();
483                    }
484                });
485                break;
486            default:
487                mSlideShowButton.setVisibility(View.GONE);
488                break;
489        }
490    }
491
492    // OnClick Listener for the playback button
493    public void onClick(View v) {
494        MessageItem mi = (MessageItem) v.getTag();
495        switch (mi.mAttachmentType) {
496            case WorkingMessage.VIDEO:
497            case WorkingMessage.AUDIO:
498            case WorkingMessage.SLIDESHOW:
499                MessageUtils.viewMmsMessageAttachment(mContext, mi.mMessageUri, mi.mSlideshow);
500                break;
501        }
502    }
503
504    public void onMessageListItemClick() {
505        URLSpan[] spans = mBodyTextView.getUrls();
506
507        if (spans.length == 0) {
508            // Do nothing.
509        } else if (spans.length == 1) {
510            Uri uri = Uri.parse(spans[0].getURL());
511            Intent intent = new Intent(Intent.ACTION_VIEW, uri);
512            intent.putExtra(Browser.EXTRA_APPLICATION_ID, mContext.getPackageName());
513            intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
514            mContext.startActivity(intent);
515        } else {
516            final java.util.ArrayList<String> urls = MessageUtils.extractUris(spans);
517
518            ArrayAdapter<String> adapter =
519                new ArrayAdapter<String>(mContext, android.R.layout.select_dialog_item, urls) {
520                public View getView(int position, View convertView, ViewGroup parent) {
521                    View v = super.getView(position, convertView, parent);
522                    try {
523                        String url = getItem(position).toString();
524                        TextView tv = (TextView) v;
525                        Drawable d = mContext.getPackageManager().getActivityIcon(new Intent(Intent.ACTION_VIEW, Uri.parse(url)));
526                        if (d != null) {
527                            d.setBounds(0, 0, d.getIntrinsicHeight(), d.getIntrinsicHeight());
528                            tv.setCompoundDrawablePadding(10);
529                            tv.setCompoundDrawables(d, null, null, null);
530                        }
531                        final String telPrefix = "tel:";
532                        if (url.startsWith(telPrefix)) {
533                            url = PhoneNumberUtils.formatNumber(
534                                            url.substring(telPrefix.length()), mDefaultCountryIso);
535                        }
536                        tv.setText(url);
537                    } catch (android.content.pm.PackageManager.NameNotFoundException ex) {
538                        ;
539                    }
540                    return v;
541                }
542            };
543
544            AlertDialog.Builder b = new AlertDialog.Builder(mContext);
545
546            DialogInterface.OnClickListener click = new DialogInterface.OnClickListener() {
547                public final void onClick(DialogInterface dialog, int which) {
548                    if (which >= 0) {
549                        Uri uri = Uri.parse(urls.get(which));
550                        Intent intent = new Intent(Intent.ACTION_VIEW, uri);
551                        intent.putExtra(Browser.EXTRA_APPLICATION_ID, mContext.getPackageName());
552                        intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
553                        mContext.startActivity(intent);
554                    }
555                    dialog.dismiss();
556                }
557            };
558
559            b.setTitle(R.string.select_link_title);
560            b.setCancelable(true);
561            b.setAdapter(adapter, click);
562
563            b.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
564                public final void onClick(DialogInterface dialog, int which) {
565                    dialog.dismiss();
566                }
567            });
568
569            b.show();
570        }
571    }
572
573
574    private void setOnClickListener(final MessageItem msgItem) {
575        switch(msgItem.mAttachmentType) {
576        case WorkingMessage.IMAGE:
577        case WorkingMessage.VIDEO:
578            mImageView.setOnClickListener(new OnClickListener() {
579                public void onClick(View v) {
580                    MessageUtils.viewMmsMessageAttachment(mContext, null, msgItem.mSlideshow);
581                }
582            });
583            mImageView.setOnLongClickListener(new OnLongClickListener() {
584                public boolean onLongClick(View v) {
585                    return v.showContextMenu();
586                }
587            });
588            break;
589
590        default:
591            mImageView.setOnClickListener(null);
592            break;
593        }
594    }
595
596    private void setErrorIndicatorClickListener(final MessageItem msgItem) {
597        String type = msgItem.mType;
598        final int what;
599        if (type.equals("sms")) {
600            what = MSG_LIST_EDIT_SMS;
601        } else {
602            what = MSG_LIST_EDIT_MMS;
603        }
604        mDeliveredIndicator.setOnClickListener(new OnClickListener() {
605            public void onClick(View v) {
606                if (null != mHandler) {
607                    Message msg = Message.obtain(mHandler, what);
608                    msg.obj = new Long(msgItem.mMsgId);
609                    msg.sendToTarget();
610                }
611            }
612        });
613    }
614
615    private void drawRightStatusIndicator(MessageItem msgItem) {
616        // Locked icon
617        if (msgItem.mLocked) {
618            mLockedIndicator.setImageResource(R.drawable.ic_lock_message_sms);
619            mLockedIndicator.setVisibility(View.VISIBLE);
620        } else {
621            mLockedIndicator.setVisibility(View.GONE);
622        }
623
624        // Delivery icon
625        if (msgItem.isOutgoingMessage() && msgItem.isFailedMessage()) {
626            mDeliveredIndicator.setImageResource(R.drawable.ic_list_alert_sms_failed);
627            setErrorIndicatorClickListener(msgItem);
628            mDeliveredIndicator.setVisibility(View.VISIBLE);
629        } else if (msgItem.mDeliveryStatus == MessageItem.DeliveryStatus.FAILED) {
630            mDeliveredIndicator.setImageResource(R.drawable.ic_list_alert_sms_failed);
631            mDeliveredIndicator.setVisibility(View.VISIBLE);
632        } else if (msgItem.mDeliveryStatus == MessageItem.DeliveryStatus.RECEIVED) {
633            mDeliveredIndicator.setImageResource(R.drawable.ic_sms_mms_delivered);
634            mDeliveredIndicator.setVisibility(View.VISIBLE);
635        } else {
636            mDeliveredIndicator.setVisibility(View.GONE);
637        }
638
639        // Message details icon
640        if (msgItem.mDeliveryStatus == MessageItem.DeliveryStatus.INFO || msgItem.mReadReport) {
641            mDetailsIndicator.setImageResource(R.drawable.ic_sms_mms_details);
642            mDetailsIndicator.setVisibility(View.VISIBLE);
643        } else {
644            mDetailsIndicator.setVisibility(View.GONE);
645        }
646    }
647
648    public void setImageRegionFit(String fit) {
649        // TODO Auto-generated method stub
650    }
651
652    public void setImageVisibility(boolean visible) {
653        // TODO Auto-generated method stub
654    }
655
656    public void setText(String name, String text) {
657        // TODO Auto-generated method stub
658    }
659
660    public void setTextVisibility(boolean visible) {
661        // TODO Auto-generated method stub
662    }
663
664    public void setVideo(String name, Uri video) {
665        inflateMmsView();
666
667        try {
668            Bitmap bitmap = VideoAttachmentView.createVideoThumbnail(mContext, video);
669            if (null == bitmap) {
670                bitmap = BitmapFactory.decodeResource(getResources(),
671                        R.drawable.ic_missing_thumbnail_video);
672            }
673            mImageView.setImageBitmap(bitmap);
674            mImageView.setVisibility(VISIBLE);
675        } catch (java.lang.OutOfMemoryError e) {
676            Log.e(TAG, "setVideo: out of memory: ", e);
677        }
678    }
679
680    public void setVideoVisibility(boolean visible) {
681        // TODO Auto-generated method stub
682    }
683
684    public void stopAudio() {
685        // TODO Auto-generated method stub
686    }
687
688    public void stopVideo() {
689        // TODO Auto-generated method stub
690    }
691
692    public void reset() {
693        if (mImageView != null) {
694            mImageView.setVisibility(GONE);
695        }
696    }
697
698    public void setVisibility(boolean visible) {
699        // TODO Auto-generated method stub
700    }
701
702    public void pauseAudio() {
703        // TODO Auto-generated method stub
704
705    }
706
707    public void pauseVideo() {
708        // TODO Auto-generated method stub
709
710    }
711
712    public void seekAudio(int seekTo) {
713        // TODO Auto-generated method stub
714
715    }
716
717    public void seekVideo(int seekTo) {
718        // TODO Auto-generated method stub
719
720    }
721}
722