1d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/*
2d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Copyright (C) 2015 The Android Open Source Project
3d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
4d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Licensed under the Apache License, Version 2.0 (the "License");
5d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * you may not use this file except in compliance with the License.
6d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * You may obtain a copy of the License at
7d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
8d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *      http://www.apache.org/licenses/LICENSE-2.0
9d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
10d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Unless required by applicable law or agreed to in writing, software
11d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * distributed under the License is distributed on an "AS IS" BASIS,
12d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * See the License for the specific language governing permissions and
14d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * limitations under the License.
15d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */
16d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
17d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpackage com.android.messaging.ui;
18d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
19d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.Context;
20d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.graphics.Rect;
21d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.util.AttributeSet;
22d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.view.LayoutInflater;
23d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.view.View;
24d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.view.animation.AnimationSet;
25d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.view.animation.ScaleAnimation;
26d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.view.animation.TranslateAnimation;
27d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.widget.FrameLayout;
28d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.widget.TextView;
29d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
30d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.R;
31d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.data.MediaPickerMessagePartData;
32d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.data.MessagePartData;
33d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.data.PendingAttachmentData;
34d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.media.ImageRequestDescriptor;
35d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.ui.AsyncImageView.AsyncImageViewDelayLoader;
36d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.AccessibilityUtil;
37d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.Assert;
38d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.UiUtils;
39d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
40d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.ArrayList;
41d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.Arrays;
42d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.Iterator;
43d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.List;
44d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
45d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd/**
46d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * Holds and displays multiple attachments in a 4x2 grid. Each preview image "tile" can take
47d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * one of three sizes - small (1x1), wide (2x1) and large (2x2). We have a number of predefined
48d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * layout settings designed for holding 2, 3, 4+ attachments (these layout settings are
49d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * tweakable by design request to allow for max flexibility). For a visual example, consider the
50d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * following attachment layout:
51d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
52d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * +---------------+----------------+
53d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * |               |                |
54d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * |               |       B        |
55d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * |               |                |
56d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * |       A       |-------+--------|
57d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * |               |       |        |
58d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * |               |   C   |    D   |
59d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * |               |       |        |
60d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * +---------------+-------+--------+
61d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd *
62d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * In the above example, the layout consists of four tiles, A-D. A is a large tile, B is a
63d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * wide tile and C & D are both small tiles. A starts at (0,0) and ends at (1,1), B starts at
64d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * (2,0) and ends at (3,0), and so on. In our layout class we'd have these tiles in the order
65d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * of A-D, so that we make sure the last tile is always the one where we can put the overflow
66d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd * indicator (e.g. "+2").
67d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd */
68d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpublic class MultiAttachmentLayout extends FrameLayout {
69d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
70d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public interface OnAttachmentClickListener {
71d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        boolean onAttachmentClick(MessagePartData attachment, Rect viewBoundsOnScreen,
72d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                boolean longPress);
73d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
74d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
75d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final int GRID_WIDTH = 4;    // in # of cells
76d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final int GRID_HEIGHT = 2;   // in # of cells
77d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
78d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
79d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Represents a preview image tile in the layout
80d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
81d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static class Tile {
82d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public final int startX;
83d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public final int startY;
84d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public final int endX;
85d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public final int endY;
86d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
87d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        private Tile(final int startX, final int startY, final int endX, final int endY) {
88d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            this.startX = startX;
89d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            this.startY = startY;
90d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            this.endX = endX;
91d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            this.endY = endY;
92d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
93d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
94d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public int getWidthMeasureSpec(final int cellWidth, final int padding) {
95d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return MeasureSpec.makeMeasureSpec((endX - startX + 1) * cellWidth - padding * 2,
96d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    MeasureSpec.EXACTLY);
97d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
98d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
99d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public int getHeightMeasureSpec(final int cellHeight, final int padding) {
100d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return MeasureSpec.makeMeasureSpec((endY - startY + 1) * cellHeight - padding * 2,
101d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    MeasureSpec.EXACTLY);
102d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
103d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
104d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public static Tile large(final int startX, final int startY) {
105d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return new Tile(startX, startY, startX + 1, startY + 1);
106d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
107d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
108d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public static Tile wide(final int startX, final int startY) {
109d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return new Tile(startX, startY, startX + 1, startY);
110d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
111d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
112d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public static Tile small(final int startX, final int startY) {
113d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return new Tile(startX, startY, startX, startY);
114d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
115d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
116d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
117d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
118d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * A layout simply contains a list of tiles, in the order of top-left -> bottom-right.
119d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
120d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static class Layout {
121d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public final List<Tile> tiles;
122d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        public Layout(final Tile[] tilesArray) {
123d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            tiles = Arrays.asList(tilesArray);
124d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
125d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
126d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
127d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
128d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * List of predefined layout configurations w.r.t no. of attachments.
129d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
130d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final Layout[] ATTACHMENT_LAYOUTS_BY_COUNT = {
131d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        null,   // Doesn't support zero attachments.
132d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        null,   // Doesn't support one attachment. Single attachment preview is used instead.
133d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        new Layout(new Tile[] { Tile.large(0, 0), Tile.large(2, 0) }),                  // 2 items
134d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        new Layout(new Tile[] { Tile.large(0, 0), Tile.wide(2, 0), Tile.wide(2, 1) }),  // 3 items
135d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        new Layout(new Tile[] { Tile.large(0, 0), Tile.wide(2, 0), Tile.small(2, 1),    // 4+ items
136d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                Tile.small(3, 1) }),
137d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    };
138d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
139d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
140d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * List of predefined RTL layout configurations w.r.t no. of attachments.
141d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
142d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final Layout[] ATTACHMENT_RTL_LAYOUTS_BY_COUNT = {
143d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        null,   // Doesn't support zero attachments.
144d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        null,   // Doesn't support one attachment. Single attachment preview is used instead.
145d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        new Layout(new Tile[] { Tile.large(2, 0), Tile.large(0, 0)}),                   // 2 items
146d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        new Layout(new Tile[] { Tile.large(2, 0), Tile.wide(0, 0), Tile.wide(0, 1) }),  // 3 items
147d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        new Layout(new Tile[] { Tile.large(2, 0), Tile.wide(0, 0), Tile.small(1, 1),    // 4+ items
148d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                Tile.small(0, 1) }),
149d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    };
150d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
151d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private Layout mCurrentLayout;
152d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private ArrayList<ViewWrapper> mPreviewViews;
153d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private int mPlusNumber;
154d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private TextView mPlusTextView;
155d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private OnAttachmentClickListener mAttachmentClickListener;
156d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private AsyncImageViewDelayLoader mImageViewDelayLoader;
157d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
158d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public MultiAttachmentLayout(final Context context, final AttributeSet attrs) {
159d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        super(context, attrs);
160d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mPreviewViews = new ArrayList<ViewWrapper>();
161d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
162d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
163d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public void bindAttachments(final Iterable<MessagePartData> attachments,
164d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final Rect transitionRect, final int count) {
165d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final ArrayList<ViewWrapper> previousViews = mPreviewViews;
166d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mPreviewViews = new ArrayList<ViewWrapper>();
167d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        removeView(mPlusTextView);
168d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mPlusTextView = null;
169d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
170d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        determineLayout(attachments, count);
171d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        buildViews(attachments, previousViews, transitionRect);
172d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
173d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Remove all previous views that couldn't be recycled.
174d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (final ViewWrapper viewWrapper : previousViews) {
175d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            removeView(viewWrapper.view);
176d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
177d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        requestLayout();
178d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
179d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
180d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public OnAttachmentClickListener getOnAttachmentClickListener() {
181d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return mAttachmentClickListener;
182d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
183d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
184d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public void setOnAttachmentClickListener(final OnAttachmentClickListener listener) {
185d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mAttachmentClickListener = listener;
186d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
187d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
188d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public void setImageViewDelayLoader(final AsyncImageViewDelayLoader delayLoader) {
189d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mImageViewDelayLoader = delayLoader;
190d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
191d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
192d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public void setColorFilter(int color) {
193d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (ViewWrapper viewWrapper : mPreviewViews) {
194d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (viewWrapper.view instanceof AsyncImageView) {
195d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                ((AsyncImageView) viewWrapper.view).setColorFilter(color);
196d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
197d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
198d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
199d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
200d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public void clearColorFilter() {
201d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (ViewWrapper viewWrapper : mPreviewViews) {
202d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (viewWrapper.view instanceof AsyncImageView) {
203d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                ((AsyncImageView) viewWrapper.view).clearColorFilter();
204d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
205d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
206d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
207d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
208d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private void determineLayout(final Iterable<MessagePartData> attachments, final int count) {
209d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        Assert.isTrue(attachments != null);
210d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final boolean isRtl = AccessibilityUtil.isLayoutRtl(getRootView());
211d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (isRtl) {
212d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mCurrentLayout = ATTACHMENT_RTL_LAYOUTS_BY_COUNT[Math.min(count,
213d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    ATTACHMENT_RTL_LAYOUTS_BY_COUNT.length - 1)];
214d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
215d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mCurrentLayout = ATTACHMENT_LAYOUTS_BY_COUNT[Math.min(count,
216d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    ATTACHMENT_LAYOUTS_BY_COUNT.length - 1)];
217d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
218d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
219d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // We must have a valid layout for the current configuration.
220d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        Assert.notNull(mCurrentLayout);
221d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
222d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mPlusNumber = count - mCurrentLayout.tiles.size();
223d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        Assert.isTrue(mPlusNumber >= 0);
224d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
225d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
226d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private void buildViews(final Iterable<MessagePartData> attachments,
227d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final ArrayList<ViewWrapper> previousViews, final Rect transitionRect) {
228d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final LayoutInflater layoutInflater = LayoutInflater.from(getContext());
229d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int count = mCurrentLayout.tiles.size();
230d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        int i = 0;
231d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final Iterator<MessagePartData> iterator = attachments.iterator();
232d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        while (iterator.hasNext() && i < count) {
233d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final MessagePartData attachment = iterator.next();
234d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            ViewWrapper attachmentWrapper = null;
235d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Try to recycle a previous view first
236d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            for (int j = 0; j < previousViews.size(); j++) {
237d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final ViewWrapper previousView = previousViews.get(j);
238d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (previousView.attachment.equals(attachment) &&
239d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        !(previousView.attachment instanceof PendingAttachmentData)) {
240d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    attachmentWrapper = previousView;
241d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    previousViews.remove(j);
242d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    break;
243d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
244d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
245d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
246d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (attachmentWrapper == null) {
247d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final View view = AttachmentPreviewFactory.createAttachmentPreview(layoutInflater,
248d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        attachment, this, AttachmentPreviewFactory.TYPE_MULTIPLE,
249d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        false /* startImageRequest */, mAttachmentClickListener);
250d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
251d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (view == null) {
252d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // createAttachmentPreview can return null if something goes wrong (e.g.
253d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // attachment has unsupported contentType)
254d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    continue;
255d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
256d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (view instanceof AsyncImageView && mImageViewDelayLoader != null) {
257d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    AsyncImageView asyncImageView = (AsyncImageView) view;
258d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    asyncImageView.setDelayLoader(mImageViewDelayLoader);
259d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
260d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                addView(view);
261d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                attachmentWrapper = new ViewWrapper(view, attachment);
262d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // Help animate from single to multi by copying over the prev location
263d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (count == 2 && i == 1 && transitionRect != null) {
264d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    attachmentWrapper.prevLeft = transitionRect.left;
265d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    attachmentWrapper.prevTop = transitionRect.top;
266d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    attachmentWrapper.prevWidth = transitionRect.width();
267d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    attachmentWrapper.prevHeight = transitionRect.height();
268d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
269d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
270d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            i++;
271d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Assert.notNull(attachmentWrapper);
272d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mPreviewViews.add(attachmentWrapper);
273d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
274d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // The first view will animate in using PopupTransitionAnimation, but the remaining
275d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // views will slide from their previous position to their new position within the
276d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // layout
277d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (i == 0) {
278d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                AttachmentPreview.tryAnimateViewIn(attachment, attachmentWrapper.view);
279d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
280d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            attachmentWrapper.needsSlideAnimation = i > 0;
281d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
282d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
283d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Build the plus text view (e.g. "+2") for when there are more attachments than what
284d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // this layout can display.
285d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (mPlusNumber > 0) {
286d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mPlusTextView = (TextView) layoutInflater.inflate(R.layout.attachment_more_text_view,
287d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    null /* parent */);
288d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mPlusTextView.setText(getResources().getString(R.string.attachment_more_items,
289d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    mPlusNumber));
290d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            addView(mPlusTextView);
291d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
292d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
293d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
294d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @Override
295d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
296d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int maxWidth = getResources().getDimensionPixelSize(
297d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                R.dimen.multiple_attachment_preview_width);
298d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int maxHeight = getResources().getDimensionPixelSize(
299d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                R.dimen.multiple_attachment_preview_height);
300d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int width = Math.min(MeasureSpec.getSize(widthMeasureSpec), maxWidth);
301d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int height = maxHeight;
302d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int cellWidth = width / GRID_WIDTH;
303d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int cellHeight = height / GRID_HEIGHT;
304d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int count = mPreviewViews.size();
305d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int padding = getResources().getDimensionPixelOffset(
306d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                R.dimen.multiple_attachment_preview_padding);
307d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (int i = 0; i < count; i++) {
308d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final View view =  mPreviewViews.get(i).view;
309d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final Tile imageTile = mCurrentLayout.tiles.get(i);
310d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            view.measure(imageTile.getWidthMeasureSpec(cellWidth, padding),
311d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    imageTile.getHeightMeasureSpec(cellHeight, padding));
312d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
313d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Now that we know the size, we can request an appropriately-sized image.
314d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (view instanceof AsyncImageView) {
315d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final ImageRequestDescriptor imageRequest =
316d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        AttachmentPreviewFactory.getImageRequestDescriptorForAttachment(
317d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                mPreviewViews.get(i).attachment,
318d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                view.getMeasuredWidth(),
319d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                view.getMeasuredHeight());
320d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                ((AsyncImageView) view).setImageResourceId(imageRequest);
321d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
322d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
323d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (i == count - 1 && mPlusTextView != null) {
324d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // The plus text view always covers the last attachment.
325d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mPlusTextView.measure(imageTile.getWidthMeasureSpec(cellWidth, padding),
326d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        imageTile.getHeightMeasureSpec(cellHeight, padding));
327d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
328d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
329d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        setMeasuredDimension(width, height);
330d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
331d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
332d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @Override
333d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected void onLayout(final boolean changed, final int left, final int top, final int right,
334d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final int bottom) {
335d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int cellWidth = getMeasuredWidth() / GRID_WIDTH;
336d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int cellHeight = getMeasuredHeight() / GRID_HEIGHT;
337d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int padding = getResources().getDimensionPixelOffset(
338d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                R.dimen.multiple_attachment_preview_padding);
339d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int count = mPreviewViews.size();
340d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (int i = 0; i < count; i++) {
341d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final ViewWrapper viewWrapper =  mPreviewViews.get(i);
342d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final View view = viewWrapper.view;
343d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final Tile imageTile = mCurrentLayout.tiles.get(i);
344d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final int tileLeft = imageTile.startX * cellWidth;
345d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final int tileTop = imageTile.startY * cellHeight;
346d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            view.layout(tileLeft + padding, tileTop + padding,
347d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    tileLeft + view.getMeasuredWidth(),
348d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    tileTop + view.getMeasuredHeight());
349d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (viewWrapper.needsSlideAnimation) {
350d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                trySlideAttachmentView(viewWrapper);
351d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                viewWrapper.needsSlideAnimation = false;
352d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } else {
353d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                viewWrapper.prevLeft = view.getLeft();
354d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                viewWrapper.prevTop = view.getTop();
355d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                viewWrapper.prevWidth = view.getWidth();
356d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                viewWrapper.prevHeight = view.getHeight();
357d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
358d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
359d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (i == count - 1 && mPlusTextView != null) {
360d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // The plus text view always covers the last attachment.
361d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mPlusTextView.layout(tileLeft + padding, tileTop + padding,
362d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        tileLeft + mPlusTextView.getMeasuredWidth(),
363d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        tileTop + mPlusTextView.getMeasuredHeight());
364d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
365d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
366d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
367d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
368d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private void trySlideAttachmentView(final ViewWrapper viewWrapper) {
369d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (!(viewWrapper.attachment instanceof MediaPickerMessagePartData)) {
370d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return;
371d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
372d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final View view = viewWrapper.view;
373d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
374d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
375d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int xOffset = viewWrapper.prevLeft - view.getLeft();
376d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int yOffset = viewWrapper.prevTop - view.getTop();
377d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final float scaleX = viewWrapper.prevWidth / (float) view.getWidth();
378d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final float scaleY = viewWrapper.prevHeight / (float) view.getHeight();
379d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
380d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (xOffset == 0 && yOffset == 0 && scaleX == 1 && scaleY == 1) {
381d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Layout hasn't changed
382d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return;
383d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
384d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
385d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final AnimationSet animationSet = new AnimationSet(
386d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                true /* shareInterpolator */);
387d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        animationSet.addAnimation(new TranslateAnimation(xOffset, 0, yOffset, 0));
388d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        animationSet.addAnimation(new ScaleAnimation(scaleX, 1, scaleY, 1));
389d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        animationSet.setDuration(
390d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                UiUtils.MEDIAPICKER_TRANSITION_DURATION);
391d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        animationSet.setInterpolator(UiUtils.DEFAULT_INTERPOLATOR);
392d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        view.startAnimation(animationSet);
393d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        view.invalidate();
394d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        viewWrapper.prevLeft = view.getLeft();
395d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        viewWrapper.prevTop = view.getTop();
396d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        viewWrapper.prevWidth = view.getWidth();
397d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        viewWrapper.prevHeight = view.getHeight();
398d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
399d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
400d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public View findViewForAttachment(final MessagePartData attachment) {
401d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        for (ViewWrapper wrapper : mPreviewViews) {
402d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (wrapper.attachment.equals(attachment) &&
403d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    !(wrapper.attachment instanceof PendingAttachmentData)) {
404d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                return wrapper.view;
405d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
406d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
407d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return null;
408d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
409d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
410d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static class ViewWrapper {
411d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final View view;
412d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final MessagePartData attachment;
413d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        boolean needsSlideAnimation;
414d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        int prevLeft;
415d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        int prevTop;
416d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        int prevWidth;
417d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        int prevHeight;
418d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
419d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        ViewWrapper(final View view, final MessagePartData attachment) {
420d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            this.view = view;
421d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            this.attachment = attachment;
422d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
423d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
424d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd}
425