MessageListItem.java revision c81bef672089654e6da3babbeb0172bd636564b2
1/*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy 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,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.email.activity;
18
19import com.android.email.R;
20import com.android.email.provider.EmailProvider;
21import com.android.email.provider.EmailContent.Message;
22
23import android.content.ClipData;
24import android.content.Context;
25import android.content.res.Resources;
26import android.graphics.Bitmap;
27import android.graphics.BitmapFactory;
28import android.graphics.Canvas;
29import android.graphics.Point;
30import android.graphics.Typeface;
31import android.graphics.drawable.Drawable;
32import android.text.TextPaint;
33import android.util.AttributeSet;
34import android.view.MotionEvent;
35import android.view.View;
36import android.widget.RelativeLayout;
37
38/**
39 * This custom View is the list item for the MessageList activity, and serves two purposes:
40 * 1.  It's a container to store message metadata (e.g. the ids of the message, mailbox, & account)
41 * 2.  It handles internal clicks such as the checkbox or the favorite star
42 */
43public class MessageListItem extends RelativeLayout {
44    private static final String TAG = "MessageListItem";
45    // Note: messagesAdapter directly fiddles with these fields.
46    /* package */ long mMessageId;
47    /* package */ long mMailboxId;
48    /* package */ long mAccountId;
49    /* package */ boolean mRead;
50    /* package */ boolean mFavorite;
51
52    private MessagesAdapter mAdapter;
53
54    private boolean mDownEvent;
55    private boolean mCachedViewPositions;
56    private int mDragRight = -1;
57    private int mCheckRight;
58    private int mStarLeft;
59
60    // Padding to increase clickable areas on left & right of each list item
61    private final static float CHECKMARK_PAD = 20.0F;
62    private final static float STAR_PAD = 20.0F;
63
64    public static final String MESSAGE_LIST_ITEMS_CLIP_LABEL =
65        "com.android.email.MESSAGE_LIST_ITEMS";
66
67    public MessageListItem(Context context) {
68        super(context);
69    }
70
71    public MessageListItem(Context context, AttributeSet attrs) {
72        super(context, attrs);
73    }
74
75    public MessageListItem(Context context, AttributeSet attrs, int defStyle) {
76        super(context, attrs, defStyle);
77    }
78
79    /**
80     * Called by the adapter at bindView() time
81     *
82     * @param adapter the adapter that creates this view
83     */
84    public void bindViewInit(MessagesAdapter adapter) {
85        mAdapter = adapter;
86        mCachedViewPositions = false;
87    }
88
89    // This is tentative drag & drop UI
90    // STOPSHIP this entire class needs to be rewritten based on the actual UI design
91    private static class ThumbnailBuilder extends DragThumbnailBuilder {
92        private static Drawable sBackground;
93        private static TextPaint sPaint;
94
95        private View mView;
96        private static final int mWidth = 250;
97        private final Bitmap mDragHandle;
98        private final float mDragHandleX;
99        private final float mDragHandleY;
100        private String mDragDesc;
101        private float mDragDescX;
102        private float mDragDescY;
103
104        public ThumbnailBuilder(View view, int count) {
105            super(view);
106            Resources resources = view.getResources();
107            mView = view;
108            mDragHandle = BitmapFactory.decodeResource(resources, R.drawable.drag_handle);
109            mDragHandleY = view.getHeight() - (mDragHandle.getHeight() / 2);
110            View handleView = view.findViewById(R.id.handle);
111            mDragHandleX = handleView.getLeft() + handleView.getPaddingLeft();
112            mDragDesc = resources.getQuantityString(R.plurals.move_messages, count, count);
113            mDragDescX = handleView.getRight() + 50;
114            // Use height of this font??
115            mDragDescY = view.getHeight() / 2;
116            if (sBackground == null) {
117                sBackground = resources.getDrawable(R.drawable.drag_background_holo);
118                sBackground.setBounds(0, 0, mWidth, view.getHeight());
119                sPaint = new TextPaint();
120                sPaint.setTypeface(Typeface.DEFAULT_BOLD);
121                sPaint.setTextSize(18);
122            }
123        }
124
125        @Override
126        public void onProvideThumbnailMetrics(Point thumbnailSize, Point thumbnailTouchPoint) {
127            //float width = mView.getWidth();
128            float height = mView.getHeight();
129            thumbnailSize.set(mWidth, (int) height);
130            thumbnailTouchPoint.set((int) mDragHandleX, (int) mDragHandleY / 2);
131        }
132
133        @Override
134        public void onDrawThumbnail(Canvas canvas) {
135            super.onDrawThumbnail(canvas);
136            sBackground.draw(canvas);
137            canvas.drawBitmap(mDragHandle, mDragHandleX, mDragHandleY, sPaint);
138            canvas.drawText(mDragDesc, mDragDescX, mDragDescY, sPaint);
139        }
140    }
141
142    /**
143     * Overriding this method allows us to "catch" clicks in the checkbox or star
144     * and process them accordingly.
145     */
146    @Override
147    public boolean onTouchEvent(MotionEvent event) {
148        boolean handled = false;
149        int touchX = (int) event.getX();
150
151        if (!mCachedViewPositions) {
152            final float paddingScale = getContext().getResources().getDisplayMetrics().density;
153            final int checkPadding = (int) ((CHECKMARK_PAD * paddingScale) + 0.5);
154            final int starPadding = (int) ((STAR_PAD * paddingScale) + 0.5);
155            View dragHandle = findViewById(R.id.handle);
156            if (dragHandle != null) {
157                mDragRight = dragHandle.getRight();
158            }
159            mCheckRight = findViewById(R.id.selected).getRight() + checkPadding;
160            mStarLeft = findViewById(R.id.favorite).getLeft() - starPadding;
161            mCachedViewPositions = true;
162        }
163
164        switch (event.getAction()) {
165            case MotionEvent.ACTION_DOWN:
166                if (touchX < mDragRight) {
167                    Context context = getContext();
168                    // Drag
169                    ClipData data = ClipData.newUri(context.getContentResolver(),
170                            MessageListItem.MESSAGE_LIST_ITEMS_CLIP_LABEL, null,
171                            Message.CONTENT_URI.buildUpon()
172                                .appendPath(Long.toString(mMessageId))
173                                .appendQueryParameter(
174                                        EmailProvider.MESSAGE_URI_PARAMETER_MAILBOX_ID,
175                                        Long.toString(mMailboxId))
176                                .build());
177                    startDrag(data, new ThumbnailBuilder(this, 1), false);
178                    handled = true;
179                } else {
180                    mDownEvent = true;
181                    if ((touchX < mCheckRight) || (touchX > mStarLeft)) {
182                        handled = true;
183                    }
184                }
185                break;
186
187            case MotionEvent.ACTION_CANCEL:
188                mDownEvent = false;
189                break;
190
191            case MotionEvent.ACTION_UP:
192                if (mDownEvent) {
193                    if (touchX < mCheckRight) {
194                        mAdapter.toggleSelected(this);
195                        handled = true;
196                    } else if (touchX > mStarLeft) {
197                        mFavorite = !mFavorite;
198                        mAdapter.updateFavorite(this, mFavorite);
199                        handled = true;
200                    }
201                }
202                break;
203        }
204
205        if (handled) {
206            postInvalidate();
207        } else {
208            handled = super.onTouchEvent(event);
209        }
210
211        return handled;
212    }
213}
214