summaryrefslogtreecommitdiffstats
path: root/src/com/android/messaging/ui/conversation/ConversationMessageBubbleView.java
blob: 395936d86c4fe8ab5b11fec11f3d1bba199bb716 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.android.messaging.ui.conversation;

import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.ObjectAnimator;
import android.content.Context;
import android.util.AttributeSet;
import android.view.ViewGroup;
import android.widget.LinearLayout;

import com.android.messaging.R;
import com.android.messaging.annotation.VisibleForAnimation;
import com.android.messaging.datamodel.data.ConversationMessageBubbleData;
import com.android.messaging.datamodel.data.ConversationMessageData;
import com.android.messaging.util.UiUtils;
import com.cyanogenmod.messaging.quickmessage.QuickMessage;

/**
 * Shows the message bubble for one conversation message. It is able to animate size changes
 * by morphing when the message content changes size.
 */
// TODO: Move functionality from ConversationMessageView into this class as appropriate
public class ConversationMessageBubbleView extends LinearLayout {
    private int mIntrinsicWidth;
    private int mMorphedWidth;
    private ObjectAnimator mAnimator;
    private boolean mShouldAnimateWidthChange;
    private final ConversationMessageBubbleData mData;
    private int mRunningStartWidth;
    private ViewGroup mBubbleBackground;

    public ConversationMessageBubbleView(final Context context, final AttributeSet attrs) {
        super(context, attrs);
        mData = new ConversationMessageBubbleData();
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        mBubbleBackground = (ViewGroup) findViewById(R.id.message_text_and_info);
    }

    @Override
    protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        final int newIntrinsicWidth = getMeasuredWidth();
        if (mIntrinsicWidth == 0 && newIntrinsicWidth != mIntrinsicWidth) {
            if (mShouldAnimateWidthChange) {
                kickOffMorphAnimation(mIntrinsicWidth, newIntrinsicWidth);
            }
            mIntrinsicWidth = newIntrinsicWidth;
        }

        if (mMorphedWidth > 0) {
            mBubbleBackground.getLayoutParams().width = mMorphedWidth;
        } else {
            mBubbleBackground.getLayoutParams().width = LayoutParams.WRAP_CONTENT;
        }
        mBubbleBackground.requestLayout();
    }

    @VisibleForAnimation
    public void setMorphWidth(final int width) {
        mMorphedWidth = width;
        requestLayout();
    }

    public void bind(final ConversationMessageData data) {
        final boolean changed = mData.bind(data);
        // Animate width change only when we are binding to the same message, so that we may
        // animate view size changes on the same message bubble due to things like status text
        // change.
        // Don't animate width change when the bubble contains attachments. Width animation is
        // only suitable for text-only messages (where the bubble size change due to status or
        // time stamp changes).
        mShouldAnimateWidthChange = !changed && !data.hasAttachments();
        if (mAnimator == null) {
            mMorphedWidth = 0;
        }
    }

    public void bind() {
        mShouldAnimateWidthChange = false;
        mMorphedWidth = 0;
    }

    public void bind(QuickMessage quickMessage) {
        bind();
    }

    public void kickOffMorphAnimation(final int oldWidth, final int newWidth) {
        if (mAnimator != null) {
            mAnimator.setIntValues(mRunningStartWidth, newWidth);
            return;
        }
        mRunningStartWidth = oldWidth;
        mAnimator = ObjectAnimator.ofInt(this, "morphWidth", oldWidth, newWidth);
        mAnimator.setDuration(UiUtils.MEDIAPICKER_TRANSITION_DURATION);
        mAnimator.addListener(new AnimatorListener() {
            @Override
            public void onAnimationStart(Animator animator) {
            }

            @Override
            public void onAnimationEnd(Animator animator) {
                mAnimator = null;
                mMorphedWidth = 0;
                // Allow the bubble to resize if, for example, the status text changed during
                // the animation.  This will snap to the bigger size if needed.  This is intentional
                // as animating immediately after looks really bad and switching layout params
                // during the original animation does not achieve the desired effect.
                mBubbleBackground.getLayoutParams().width = LayoutParams.WRAP_CONTENT;
                mBubbleBackground.requestLayout();
            }

            @Override
            public void onAnimationCancel(Animator animator) {
            }

            @Override
            public void onAnimationRepeat(Animator animator) {
            }
        });
        mAnimator.start();
    }
}