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.animation.Animator;
20d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.animation.ObjectAnimator;
21d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.content.Context;
22d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.graphics.Rect;
23d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.os.Handler;
24d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.os.Looper;
25d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.util.AttributeSet;
26d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.view.LayoutInflater;
27d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.view.View;
28d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.widget.FrameLayout;
29d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.widget.ImageButton;
30d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport android.widget.ScrollView;
31d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
32d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.R;
33d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.annotation.VisibleForAnimation;
34d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.data.DraftMessageData;
35d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.data.MediaPickerMessagePartData;
36d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.data.MessagePartData;
37d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.datamodel.data.PendingAttachmentData;
38d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.ui.MultiAttachmentLayout.OnAttachmentClickListener;
39d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.ui.animation.PopupTransitionAnimation;
40d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.ui.conversation.ComposeMessageView;
41d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.ui.conversation.ConversationFragment;
42d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.Assert;
43d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.ThreadUtil;
44d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport com.android.messaging.util.UiUtils;
45d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
46d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.ArrayList;
47d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddimport java.util.List;
48d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
49d3b009ae55651f1e60950342468e3c37fdeb0796Mike Doddpublic class AttachmentPreview extends ScrollView implements OnAttachmentClickListener {
50d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private FrameLayout mAttachmentView;
51d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private ComposeMessageView mComposeMessageView;
52d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private ImageButton mCloseButton;
53d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private int mAnimatedHeight = -1;
54d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private Animator mCloseGapAnimator;
55d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private boolean mPendingFirstUpdate;
56d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private Handler mHandler;
57d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private Runnable mHideRunnable;
58d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private boolean mPendingHideCanceled;
59d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
60d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private static final int CLOSE_BUTTON_REVEAL_STAGGER_MILLIS = 300;
61d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
62d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public AttachmentPreview(final Context context, final AttributeSet attrs) {
63d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        super(context, attrs);
64d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mHandler = new Handler(Looper.getMainLooper());
65d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
66d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
67d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @Override
68d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected void onFinishInflate() {
69d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        super.onFinishInflate();
70d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mCloseButton = (ImageButton) findViewById(R.id.close_button);
71d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mCloseButton.setOnClickListener(new OnClickListener() {
72d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            @Override
73d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            public void onClick(final View view) {
74d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mComposeMessageView.clearAttachments();
75d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
76d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        });
77d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
78d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mAttachmentView = (FrameLayout) findViewById(R.id.attachment_view);
79d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
80d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // The attachment preview is a scroll view so that it can show the bottom portion of the
81d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // attachment whenever the space is tight (e.g. when in landscape mode). Per design
82d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // request we'd like to make the attachment view always scrolled to the bottom.
83d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        addOnLayoutChangeListener(new OnLayoutChangeListener() {
84d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            @Override
85d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            public void onLayoutChange(final View v, final int left, final int top, final int right,
86d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    final int bottom, final int oldLeft, final int oldTop, final int oldRight,
87d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    final int oldBottom) {
88d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                post(new Runnable() {
89d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    @Override
90d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    public void run() {
91d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        final int childCount = getChildCount();
92d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        if (childCount > 0) {
93d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            final View lastChild = getChildAt(childCount - 1);
94d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            scrollTo(getScrollX(), lastChild.getBottom() - getHeight());
95d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        }
96d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
97d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                });
98d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
99d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        });
100d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mPendingFirstUpdate = true;
101d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
102d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
103d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public void setComposeMessageView(final ComposeMessageView composeMessageView) {
104d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mComposeMessageView = composeMessageView;
105d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
106d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
107d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @Override
108d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
109d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
110d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (mAnimatedHeight >= 0) {
111d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            setMeasuredDimension(getMeasuredWidth(), mAnimatedHeight);
112d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
113d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
114d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
115d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private void cancelPendingHide() {
116d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mPendingHideCanceled = true;
117d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
118d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
119d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public void hideAttachmentPreview() {
120d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (getVisibility() != GONE) {
121d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            UiUtils.revealOrHideViewWithAnimation(mCloseButton, GONE,
122d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    null /* onFinishRunnable */);
123d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            startCloseGapAnimationOnAttachmentClear();
124d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
125d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (mAttachmentView.getChildCount() > 0) {
126d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mPendingHideCanceled = false;
127d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final View viewToHide = mAttachmentView.getChildCount() > 1 ?
128d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        mAttachmentView : mAttachmentView.getChildAt(0);
129d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                UiUtils.revealOrHideViewWithAnimation(viewToHide, INVISIBLE,
130d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        new Runnable() {
131d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            @Override
132d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            public void run() {
133d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                // Only hide if we are didn't get overruled by showing
134d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                if (!mPendingHideCanceled) {
135d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                    mAttachmentView.removeAllViews();
136d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                    setVisibility(GONE);
137d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                }
138d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            }
139d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        });
140d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } else {
141d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mAttachmentView.removeAllViews();
142d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                setVisibility(GONE);
143d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
144d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
145d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
146d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
147d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    // returns true if we have attachments
148d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public boolean onAttachmentsChanged(final DraftMessageData draftMessageData) {
149d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final boolean isFirstUpdate = mPendingFirstUpdate;
150d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final List<MessagePartData> attachments = draftMessageData.getReadOnlyAttachments();
151d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final List<PendingAttachmentData> pendingAttachments =
152d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                draftMessageData.getReadOnlyPendingAttachments();
153d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
154d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Any change in attachments would invalidate the animated height animation.
155d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        cancelCloseGapAnimation();
156d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mPendingFirstUpdate = false;
157d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
158d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final int combinedAttachmentCount = attachments.size() + pendingAttachments.size();
159d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mCloseButton.setContentDescription(getResources()
160d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                .getQuantityString(R.plurals.attachment_preview_close_content_description,
161d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        combinedAttachmentCount));
162d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (combinedAttachmentCount == 0) {
163d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mHideRunnable = new Runnable() {
164d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                @Override
165d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                public void run() {
166d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    mHideRunnable = null;
167d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    // Only start the hiding if there are still no attachments
168d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (attachments.size() + pendingAttachments.size() == 0) {
169d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        hideAttachmentPreview();
170d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
171d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
172d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            };
173d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (draftMessageData.isSending()) {
174d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // Wait to hide until the message is ready to start animating
175d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // We'll execute immediately when the animation triggers
176d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mHandler.postDelayed(mHideRunnable,
177d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        ConversationFragment.MESSAGE_ANIMATION_MAX_WAIT);
178d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            } else {
179d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // Run immediately when clearing attachments
180d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mHideRunnable.run();
181d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
182d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return false;
183d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
184d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
185d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        cancelPendingHide();  // We're showing
186d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (getVisibility() != VISIBLE) {
187d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            setVisibility(VISIBLE);
188d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mAttachmentView.setVisibility(VISIBLE);
189d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
190d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // Don't animate in the close button if this is the first update after view creation.
191d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            // This is the initial draft load from database for pre-existing drafts.
192d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (!isFirstUpdate) {
193d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // Reveal the close button after the view animates in.
194d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mCloseButton.setVisibility(INVISIBLE);
195d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                ThreadUtil.getMainThreadHandler().postDelayed(new Runnable() {
196d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    @Override
197d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    public void run() {
198d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        UiUtils.revealOrHideViewWithAnimation(mCloseButton, VISIBLE,
199d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                null /* onFinishRunnable */);
200d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
201d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }, UiUtils.MEDIAPICKER_TRANSITION_DURATION + CLOSE_BUTTON_REVEAL_STAGGER_MILLIS);
202d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
203d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
204d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
205d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Merge the pending attachment list with real attachment.  Design would prefer these be
206d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // in LIFO order user can see added images past the 5th one but we also want them to be in
207d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // order and we want it to be WYSIWYG.
208d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final List<MessagePartData> combinedAttachments = new ArrayList<>();
209d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        combinedAttachments.addAll(attachments);
210d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        combinedAttachments.addAll(pendingAttachments);
211d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
212d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        final LayoutInflater layoutInflater = LayoutInflater.from(getContext());
213d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (combinedAttachmentCount > 1) {
214d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            MultiAttachmentLayout multiAttachmentLayout = null;
215d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            Rect transitionRect = null;
216d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (mAttachmentView.getChildCount() > 0) {
217d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final View firstChild = mAttachmentView.getChildAt(0);
218d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (firstChild instanceof MultiAttachmentLayout) {
219d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    Assert.equals(1, mAttachmentView.getChildCount());
220d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    multiAttachmentLayout = (MultiAttachmentLayout) firstChild;
221d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    multiAttachmentLayout.bindAttachments(combinedAttachments,
222d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            null /* transitionRect */, combinedAttachmentCount);
223d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                } else {
224d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    transitionRect = new Rect(firstChild.getLeft(), firstChild.getTop(),
225d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            firstChild.getRight(), firstChild.getBottom());
226d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
227d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
228d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (multiAttachmentLayout == null) {
229d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                multiAttachmentLayout = AttachmentPreviewFactory.createMultiplePreview(
230d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        getContext(), this);
231d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                multiAttachmentLayout.bindAttachments(combinedAttachments, transitionRect,
232d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        combinedAttachmentCount);
233d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mAttachmentView.removeAllViews();
234d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mAttachmentView.addView(multiAttachmentLayout);
235d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
236d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        } else {
237d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final MessagePartData attachment = combinedAttachments.get(0);
238d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            boolean shouldAnimate = true;
239d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (mAttachmentView.getChildCount() > 0) {
240d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // If we are going from N->1 attachments, try to use the current bounds
241d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                // bounds as the starting rect.
242d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                shouldAnimate = false;
243d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                final View firstChild = mAttachmentView.getChildAt(0);
244d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (firstChild instanceof MultiAttachmentLayout &&
245d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        attachment instanceof MediaPickerMessagePartData) {
246d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    final View leftoverView = ((MultiAttachmentLayout) firstChild)
247d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            .findViewForAttachment(attachment);
248d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    if (leftoverView != null) {
249d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        final Rect currentRect = UiUtils.getMeasuredBoundsOnScreen(leftoverView);
250d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        if (!currentRect.isEmpty() &&
251d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                                attachment instanceof MediaPickerMessagePartData) {
252d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            ((MediaPickerMessagePartData) attachment).setStartRect(currentRect);
253d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                            shouldAnimate = true;
254d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                        }
255d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    }
256d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
257d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
258d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mAttachmentView.removeAllViews();
259d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final View attachmentView = AttachmentPreviewFactory.createAttachmentPreview(
260d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    layoutInflater, attachment, mAttachmentView,
261d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    AttachmentPreviewFactory.TYPE_SINGLE, true /* startImageRequest */, this);
262d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            if (attachmentView != null) {
263d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                mAttachmentView.addView(attachmentView);
264d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                if (shouldAnimate) {
265d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                    tryAnimateViewIn(attachment, attachmentView);
266d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd                }
267d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            }
268d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
269d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return true;
270d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
271d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
272d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public void onMessageAnimationStart() {
273d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (mHideRunnable == null) {
274d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return;
275d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
276d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
277d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Run the hide animation at the same time as the message animation
278d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mHandler.removeCallbacks(mHideRunnable);
279d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        setVisibility(View.INVISIBLE);
280d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mHideRunnable.run();
281d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
282d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
283d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    static void tryAnimateViewIn(final MessagePartData attachmentData, final View view) {
284d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (attachmentData instanceof MediaPickerMessagePartData) {
285d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final Rect startRect = ((MediaPickerMessagePartData) attachmentData).getStartRect();
286d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            new PopupTransitionAnimation(startRect, view).startAfterLayoutComplete();
287d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
288d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
289d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
290d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @VisibleForAnimation
291d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public void setAnimatedHeight(final int animatedHeight) {
292d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (mAnimatedHeight != animatedHeight) {
293d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mAnimatedHeight = animatedHeight;
294d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            requestLayout();
295d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
296d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
297d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
298d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    /**
299d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * Kicks off an animation to animate the layout change for closing the gap between the
300d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     * message list and the compose message box when the attachments are cleared.
301d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd     */
302d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private void startCloseGapAnimationOnAttachmentClear() {
303d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        // Cancel existing animation.
304d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        cancelCloseGapAnimation();
305d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mCloseGapAnimator = ObjectAnimator.ofInt(this, "animatedHeight", getHeight(), 0);
306d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mCloseGapAnimator.start();
307d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
308d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
309d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    private void cancelCloseGapAnimation() {
310d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (mCloseGapAnimator != null) {
311d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mCloseGapAnimator.cancel();
312d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mCloseGapAnimator = null;
313d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
314d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        mAnimatedHeight = -1;
315d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
316d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
317d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    @Override
318d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    public boolean onAttachmentClick(final MessagePartData attachment,
319d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            final Rect viewBoundsOnScreen, final boolean longPress) {
320d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (longPress) {
321d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mComposeMessageView.onAttachmentPreviewLongClicked();
322d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return true;
323d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
324d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd
325d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        if (!(attachment instanceof PendingAttachmentData) && attachment.isImage()) {
326d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            mComposeMessageView.displayPhoto(attachment.getContentUri(), viewBoundsOnScreen);
327d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd            return true;
328d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        }
329d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd        return false;
330d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd    }
331d3b009ae55651f1e60950342468e3c37fdeb0796Mike Dodd}
332