1f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein/*
2f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein * Copyright (C) 2011 The Android Open Source Project
3f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein *
4f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein * Licensed under the Apache License, Version 2.0 (the "License");
5f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein * you may not use this file except in compliance with the License.
6f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein * You may obtain a copy of the License at
7f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein *
8f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein *      http://www.apache.org/licenses/LICENSE-2.0
9f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein *
10f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein * Unless required by applicable law or agreed to in writing, software
11f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein * distributed under the License is distributed on an "AS IS" BASIS,
12f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein * See the License for the specific language governing permissions and
14f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein * limitations under the License.
15f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein */
16f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein
17237129ddf57a1e25469d8990322fb7913e18ae20Andrew Sappersteinpackage com.android.mail.ui;
18f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein
198081df46ef5a7794374e41cd1836e778a2da9b31Paul Westbrookimport android.app.FragmentManager;
20f986850eb04ff614feb915e178227c4f53ca695bAndrew Sappersteinimport android.content.Context;
21e1557036849265afc24528be9effbe299b640bffAndrew Sappersteinimport android.content.res.Resources;
2262066e47fe69c33b60ed970e46809ba81d044064Mark Weiimport android.graphics.Bitmap;
23e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sappersteinimport android.util.AttributeSet;
24f986850eb04ff614feb915e178227c4f53ca695bAndrew Sappersteinimport android.view.LayoutInflater;
25f986850eb04ff614feb915e178227c4f53ca695bAndrew Sappersteinimport android.view.View;
26f986850eb04ff614feb915e178227c4f53ca695bAndrew Sappersteinimport android.widget.FrameLayout;
27f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein
28e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sappersteinimport com.android.mail.R;
294f347e811052f446c3958c76db278bcd7b39a44fAndy Huangimport com.android.mail.browse.ConversationMessage;
30237129ddf57a1e25469d8990322fb7913e18ae20Andrew Sappersteinimport com.android.mail.browse.MessageAttachmentTile;
31237129ddf57a1e25469d8990322fb7913e18ae20Andrew Sappersteinimport com.android.mail.compose.ComposeAttachmentTile;
324f347e811052f446c3958c76db278bcd7b39a44fAndy Huangimport com.android.mail.photo.MailPhotoViewActivity;
334f347e811052f446c3958c76db278bcd7b39a44fAndy Huangimport com.android.mail.providers.Account;
34f986850eb04ff614feb915e178227c4f53ca695bAndrew Sappersteinimport com.android.mail.providers.Attachment;
3562066e47fe69c33b60ed970e46809ba81d044064Mark Weiimport com.android.mail.ui.AttachmentTile.AttachmentPreview;
3662066e47fe69c33b60ed970e46809ba81d044064Mark Weiimport com.android.mail.ui.AttachmentTile.AttachmentPreviewCache;
37db65689be3ada3965c12312ad60b2a5d6917a98eAndrew Sappersteinimport com.android.mail.utils.ViewUtils;
3862066e47fe69c33b60ed970e46809ba81d044064Mark Weiimport com.google.common.collect.Lists;
3962066e47fe69c33b60ed970e46809ba81d044064Mark Weiimport com.google.common.collect.Maps;
4062066e47fe69c33b60ed970e46809ba81d044064Mark Wei
4162066e47fe69c33b60ed970e46809ba81d044064Mark Weiimport java.util.ArrayList;
4262066e47fe69c33b60ed970e46809ba81d044064Mark Weiimport java.util.HashMap;
43f986850eb04ff614feb915e178227c4f53ca695bAndrew Sappersteinimport java.util.List;
44f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein
45f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein/**
46237129ddf57a1e25469d8990322fb7913e18ae20Andrew Sapperstein * Acts as a grid composed of {@link AttachmentTile}s.
47f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein */
484f347e811052f446c3958c76db278bcd7b39a44fAndy Huangpublic class AttachmentTileGrid extends FrameLayout implements AttachmentPreviewCache,
494f347e811052f446c3958c76db278bcd7b39a44fAndy Huang        MessageAttachmentTile.PhotoViewHandler {
5069c4ddb7a49f11377143c9ff1c7b85b2450449e9Mark Wei    private final LayoutInflater mInflater;
51e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein    private final int mTileMinSize;
52e1557036849265afc24528be9effbe299b640bffAndrew Sapperstein    private final int mTilePadding;
53e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein    private int mColumnCount;
544cb51dbce9635f4bf68a6de88f759e2f86d20325Andrew Sapperstein    private List<Attachment> mAttachments;
5569c4ddb7a49f11377143c9ff1c7b85b2450449e9Mark Wei    private final HashMap<String, AttachmentPreview> mAttachmentPreviews;
568081df46ef5a7794374e41cd1836e778a2da9b31Paul Westbrook    private FragmentManager mFragmentManager;
574f347e811052f446c3958c76db278bcd7b39a44fAndy Huang    private Account mAccount;
58833123d9c31b0b2dd23f7f74738c5bccf8a546d3Andrew Sapperstein    private ConversationMessage mMessage;
59f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein
60e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein    public AttachmentTileGrid(Context context, AttributeSet attrs) {
61e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein        super(context, attrs);
62f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein        mInflater = LayoutInflater.from(context);
63e1557036849265afc24528be9effbe299b640bffAndrew Sapperstein        final Resources res = context.getResources();
64e1557036849265afc24528be9effbe299b640bffAndrew Sapperstein        mTileMinSize = res.getDimensionPixelSize(R.dimen.attachment_tile_min_size);
65e1557036849265afc24528be9effbe299b640bffAndrew Sapperstein        mTilePadding = res.getDimensionPixelSize(R.dimen.attachment_tile_padding);
6662066e47fe69c33b60ed970e46809ba81d044064Mark Wei        mAttachmentPreviews = Maps.newHashMap();
67f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein    }
68f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein
69f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein    /**
70e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein     * Configures the grid to add {@link Attachment}s information to the views.
71f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein     */
724f347e811052f446c3958c76db278bcd7b39a44fAndy Huang    public void configureGrid(FragmentManager fragmentManager, Account account,
734f347e811052f446c3958c76db278bcd7b39a44fAndy Huang            ConversationMessage message, List<Attachment> list, boolean loaderResult) {
744f347e811052f446c3958c76db278bcd7b39a44fAndy Huang
758081df46ef5a7794374e41cd1836e778a2da9b31Paul Westbrook        mFragmentManager = fragmentManager;
764f347e811052f446c3958c76db278bcd7b39a44fAndy Huang        mAccount = account;
774f347e811052f446c3958c76db278bcd7b39a44fAndy Huang        mMessage = message;
784cb51dbce9635f4bf68a6de88f759e2f86d20325Andrew Sapperstein        mAttachments = list;
79e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein        // Adding tiles to grid and filling in attachment information
80e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein        int index = 0;
81e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein        for (Attachment attachment : list) {
828081df46ef5a7794374e41cd1836e778a2da9b31Paul Westbrook            addMessageTileFromAttachment(attachment, index++, loaderResult);
83f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein        }
84f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein    }
85f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein
868081df46ef5a7794374e41cd1836e778a2da9b31Paul Westbrook    private void addMessageTileFromAttachment(Attachment attachment, int index,
878081df46ef5a7794374e41cd1836e778a2da9b31Paul Westbrook            boolean loaderResult) {
888081df46ef5a7794374e41cd1836e778a2da9b31Paul Westbrook        final MessageAttachmentTile attachmentTile;
89f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein
90e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein        if (getChildCount() <= index) {
91f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein            attachmentTile = MessageAttachmentTile.inflate(mInflater, this);
928081df46ef5a7794374e41cd1836e778a2da9b31Paul Westbrook            attachmentTile.initialize(mFragmentManager);
934f347e811052f446c3958c76db278bcd7b39a44fAndy Huang            attachmentTile.setPhotoViewHandler(this);
94f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein            addView(attachmentTile);
95f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein        } else {
968081df46ef5a7794374e41cd1836e778a2da9b31Paul Westbrook            attachmentTile = (MessageAttachmentTile) getChildAt(index);
97f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein        }
98f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein
994f347e811052f446c3958c76db278bcd7b39a44fAndy Huang        attachmentTile.render(attachment, index, this, loaderResult);
100f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein    }
101f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein
102237129ddf57a1e25469d8990322fb7913e18ae20Andrew Sapperstein    public ComposeAttachmentTile addComposeTileFromAttachment(Attachment attachment) {
103237129ddf57a1e25469d8990322fb7913e18ae20Andrew Sapperstein        final ComposeAttachmentTile attachmentTile =
104237129ddf57a1e25469d8990322fb7913e18ae20Andrew Sapperstein                ComposeAttachmentTile.inflate(mInflater, this);
105237129ddf57a1e25469d8990322fb7913e18ae20Andrew Sapperstein
106237129ddf57a1e25469d8990322fb7913e18ae20Andrew Sapperstein        addView(attachmentTile);
1074f347e811052f446c3958c76db278bcd7b39a44fAndy Huang        attachmentTile.render(attachment, this);
108237129ddf57a1e25469d8990322fb7913e18ae20Andrew Sapperstein
109237129ddf57a1e25469d8990322fb7913e18ae20Andrew Sapperstein        return attachmentTile;
110237129ddf57a1e25469d8990322fb7913e18ae20Andrew Sapperstein    }
111237129ddf57a1e25469d8990322fb7913e18ae20Andrew Sapperstein
112f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein    @Override
1134f347e811052f446c3958c76db278bcd7b39a44fAndy Huang    public void viewPhoto(MessageAttachmentTile source) {
1144f347e811052f446c3958c76db278bcd7b39a44fAndy Huang        final int photoIndex = indexOfChild(source);
1154f347e811052f446c3958c76db278bcd7b39a44fAndy Huang
1164f347e811052f446c3958c76db278bcd7b39a44fAndy Huang        MailPhotoViewActivity.startMailPhotoViewActivity(getContext(), mAccount.getEmailAddress(),
117a00a413f293b73b8b6d16c0707d08f881fd92e1cMartin Hibdon                mAccount.getType(), mMessage, photoIndex);
1184f347e811052f446c3958c76db278bcd7b39a44fAndy Huang    }
1194f347e811052f446c3958c76db278bcd7b39a44fAndy Huang
1204f347e811052f446c3958c76db278bcd7b39a44fAndy Huang    @Override
121f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
122f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein        onMeasureForTiles(widthMeasureSpec);
123f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein    }
124f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein
125f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein    private void onMeasureForTiles(int widthMeasureSpec) {
126f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein        final int width = MeasureSpec.getSize(widthMeasureSpec);
127f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein
128f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein        final int childCount = getChildCount();
129f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein        if (childCount == 0) {
130f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein            // Just in case...
131f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein            setMeasuredDimension(width, 0);
132f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein            return;
133f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein        }
134f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein
135e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein        // Divide width by minimum tile size to get the number of columns.
136e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein        // Truncation will ensure that the minimum will always be the minimum
137e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein        // but that the tiles can (and likely will) grow larger.
138e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein        mColumnCount = width / mTileMinSize;
139e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein
140e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein        // Just in case...
141e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein        if (mColumnCount == 0) {
142e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein            mColumnCount = 1;
143e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein        }
144e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein
145f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein        // 1. Calculate image size.
146f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein        //      = [total width] / [child count]
147f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein        //
148f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein        // 2. Set it to width/height of each children.
149e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein        //    If we have a remainder, some tiles will have
150e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein        //    1 pixel larger width than its height.
151f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein        //
152f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein        // 3. Set the dimensions of itself.
153f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein        //    Let width = given width.
154e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein        //    Let height = image size + bottom padding.
155a6e8789043b567a54cb930dd785fba573cf65f5cMark Wei
156e1557036849265afc24528be9effbe299b640bffAndrew Sapperstein        final int widthMinusPadding = width - (mColumnCount - 1) * mTilePadding;
157e1557036849265afc24528be9effbe299b640bffAndrew Sapperstein
158e1557036849265afc24528be9effbe299b640bffAndrew Sapperstein        final int imageSize = (widthMinusPadding) / mColumnCount;
159e1557036849265afc24528be9effbe299b640bffAndrew Sapperstein        final int remainder = widthMinusPadding - (imageSize * mColumnCount);
160f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein
161f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein        for (int i = 0; i < childCount; i++) {
162f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein            final View child = getChildAt(i);
163e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein            // Compensate for the remainder
164e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein            final int childWidth = imageSize + (i < remainder ? 1 : 0);
165f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein            child.measure(
166f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein                    MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY),
167e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein                    MeasureSpec.makeMeasureSpec(imageSize, MeasureSpec.EXACTLY)
168f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein                    );
169f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein        }
170e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein
171e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein        // Calculate the number of rows so we can get the proper height.
172e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein        // Then multiply by the height of one tile to get the grid height.
173e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein        final int numRows = ((childCount - 1) / mColumnCount) + 1;
174e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein        setMeasuredDimension(width,
175e1557036849265afc24528be9effbe299b640bffAndrew Sapperstein                numRows * (imageSize + getChildAt(0).getPaddingBottom()) +
176e1557036849265afc24528be9effbe299b640bffAndrew Sapperstein                (numRows - 1) * mTilePadding);
177e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein    }
178e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein
179e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein    @Override
180e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
181e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein        onLayoutForTiles();
182e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein    }
183e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein
184e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein    private void onLayoutForTiles() {
185e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein        final int count = getChildCount();
186db65689be3ada3965c12312ad60b2a5d6917a98eAndrew Sapperstein        if (count == 0) {
187db65689be3ada3965c12312ad60b2a5d6917a98eAndrew Sapperstein            return;
188db65689be3ada3965c12312ad60b2a5d6917a98eAndrew Sapperstein        }
189db65689be3ada3965c12312ad60b2a5d6917a98eAndrew Sapperstein
190e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein        boolean skipBeginningOfRowFirstTime = true;
191db65689be3ada3965c12312ad60b2a5d6917a98eAndrew Sapperstein        final boolean isRtl = ViewUtils.isViewRtl(this);
192db65689be3ada3965c12312ad60b2a5d6917a98eAndrew Sapperstein        final int width = getMeasuredWidth();
193e1557036849265afc24528be9effbe299b640bffAndrew Sapperstein        int childLeft = (isRtl) ? width - getChildAt(0).getMeasuredWidth() : 0;
194db65689be3ada3965c12312ad60b2a5d6917a98eAndrew Sapperstein        int childTop = 0;
195e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein
196e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein        // Layout the grid.
197e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein        for (int i = 0; i < count; i++) {
198e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein            final View child = getChildAt(i);
199e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein
200e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein            // Note MeasuredWidth and MeasuredHeight include the padding.
201e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein            final int childWidth = child.getMeasuredWidth();
202e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein            final int childHeight = child.getMeasuredHeight();
203e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein
204e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein            // If we're at the beginning of a row and it is not the first row
205e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein            // in the grid, reset childLeft to 0 and update childTop
206e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein            // to reflect the top of the new row.
207e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein            if (!skipBeginningOfRowFirstTime && i % mColumnCount == 0) {
208db65689be3ada3965c12312ad60b2a5d6917a98eAndrew Sapperstein                childLeft = (isRtl) ? width - childWidth : 0;
209e1557036849265afc24528be9effbe299b640bffAndrew Sapperstein                childTop += childHeight + mTilePadding;
210e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein            } else {
211e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein                skipBeginningOfRowFirstTime = false;
212e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein            }
213e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein
214e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein            child.layout(childLeft, childTop,
215e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein                    childLeft + childWidth, childTop + childHeight);
216db65689be3ada3965c12312ad60b2a5d6917a98eAndrew Sapperstein
217db65689be3ada3965c12312ad60b2a5d6917a98eAndrew Sapperstein            if (isRtl) {
218e1557036849265afc24528be9effbe299b640bffAndrew Sapperstein                childLeft -= childWidth - mTilePadding;
219db65689be3ada3965c12312ad60b2a5d6917a98eAndrew Sapperstein            } else {
220e1557036849265afc24528be9effbe299b640bffAndrew Sapperstein                childLeft += childWidth + mTilePadding;
221db65689be3ada3965c12312ad60b2a5d6917a98eAndrew Sapperstein            }
222e4798f5d8bd07eb39bf9dac57fd2a304b53916a0Andrew Sapperstein        }
223f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein    }
224f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein
225f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein    @Override
226f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein    public void sendAccessibilityEvent(int eventType) {
227f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein        // This method is called when the child tile is INVISIBLE (meaning "empty"), and the
228f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein        // Accessibility Manager needs to find alternative content description to speak.
229f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein        // Here, we ignore the default behavior, since we don't want to let the manager speak
230f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein        // a contact name for the tile next to the INVISIBLE tile.
231f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein    }
2324cb51dbce9635f4bf68a6de88f759e2f86d20325Andrew Sapperstein
2334cb51dbce9635f4bf68a6de88f759e2f86d20325Andrew Sapperstein    public List<Attachment> getAttachments() {
2344cb51dbce9635f4bf68a6de88f759e2f86d20325Andrew Sapperstein        return mAttachments;
2354cb51dbce9635f4bf68a6de88f759e2f86d20325Andrew Sapperstein    }
23662066e47fe69c33b60ed970e46809ba81d044064Mark Wei
23762066e47fe69c33b60ed970e46809ba81d044064Mark Wei    public ArrayList<AttachmentPreview> getAttachmentPreviews() {
23862066e47fe69c33b60ed970e46809ba81d044064Mark Wei        return Lists.newArrayList(mAttachmentPreviews.values());
23962066e47fe69c33b60ed970e46809ba81d044064Mark Wei    }
24062066e47fe69c33b60ed970e46809ba81d044064Mark Wei
24162066e47fe69c33b60ed970e46809ba81d044064Mark Wei    public void setAttachmentPreviews(ArrayList<AttachmentPreview> previews) {
24262066e47fe69c33b60ed970e46809ba81d044064Mark Wei        if (previews != null) {
24362066e47fe69c33b60ed970e46809ba81d044064Mark Wei            for (AttachmentPreview preview : previews) {
24462066e47fe69c33b60ed970e46809ba81d044064Mark Wei                mAttachmentPreviews.put(preview.attachmentIdentifier, preview);
24562066e47fe69c33b60ed970e46809ba81d044064Mark Wei            }
24662066e47fe69c33b60ed970e46809ba81d044064Mark Wei        }
24762066e47fe69c33b60ed970e46809ba81d044064Mark Wei    }
24862066e47fe69c33b60ed970e46809ba81d044064Mark Wei
24962066e47fe69c33b60ed970e46809ba81d044064Mark Wei    /*
25062066e47fe69c33b60ed970e46809ba81d044064Mark Wei     * Save the preview for an attachment
25162066e47fe69c33b60ed970e46809ba81d044064Mark Wei     */
25262066e47fe69c33b60ed970e46809ba81d044064Mark Wei    @Override
25362066e47fe69c33b60ed970e46809ba81d044064Mark Wei    public void set(Attachment attachment, Bitmap preview) {
25469c4ddb7a49f11377143c9ff1c7b85b2450449e9Mark Wei        final String attachmentIdentifier = attachment.getIdentifierUri().toString();
25562066e47fe69c33b60ed970e46809ba81d044064Mark Wei        if (attachmentIdentifier != null) {
25662066e47fe69c33b60ed970e46809ba81d044064Mark Wei            mAttachmentPreviews.put(
25762066e47fe69c33b60ed970e46809ba81d044064Mark Wei                    attachmentIdentifier, new AttachmentPreview(attachment, preview));
25862066e47fe69c33b60ed970e46809ba81d044064Mark Wei        }
25962066e47fe69c33b60ed970e46809ba81d044064Mark Wei    }
26062066e47fe69c33b60ed970e46809ba81d044064Mark Wei
26162066e47fe69c33b60ed970e46809ba81d044064Mark Wei    /*
26262066e47fe69c33b60ed970e46809ba81d044064Mark Wei     * Returns a saved preview that was previously set
26362066e47fe69c33b60ed970e46809ba81d044064Mark Wei     */
26462066e47fe69c33b60ed970e46809ba81d044064Mark Wei    @Override
26562066e47fe69c33b60ed970e46809ba81d044064Mark Wei    public Bitmap get(Attachment attachment) {
26669c4ddb7a49f11377143c9ff1c7b85b2450449e9Mark Wei        final String attachmentIdentifier = attachment.getIdentifierUri().toString();
26762066e47fe69c33b60ed970e46809ba81d044064Mark Wei        if (attachmentIdentifier != null) {
26862066e47fe69c33b60ed970e46809ba81d044064Mark Wei            final AttachmentPreview attachmentPreview = mAttachmentPreviews.get(
26962066e47fe69c33b60ed970e46809ba81d044064Mark Wei                    attachmentIdentifier);
27062066e47fe69c33b60ed970e46809ba81d044064Mark Wei            if (attachmentPreview != null) {
27162066e47fe69c33b60ed970e46809ba81d044064Mark Wei                return attachmentPreview.preview;
27262066e47fe69c33b60ed970e46809ba81d044064Mark Wei            }
27362066e47fe69c33b60ed970e46809ba81d044064Mark Wei        }
27462066e47fe69c33b60ed970e46809ba81d044064Mark Wei        return null;
27562066e47fe69c33b60ed970e46809ba81d044064Mark Wei    }
276f986850eb04ff614feb915e178227c4f53ca695bAndrew Sapperstein}
277