Home | History | Annotate | Download | only in conversation
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package com.android.messaging.ui.conversation;
     17 
     18 import android.animation.Animator;
     19 import android.animation.Animator.AnimatorListener;
     20 import android.animation.ObjectAnimator;
     21 import android.content.Context;
     22 import android.util.AttributeSet;
     23 import android.view.ViewGroup;
     24 import android.widget.LinearLayout;
     25 
     26 import com.android.messaging.R;
     27 import com.android.messaging.annotation.VisibleForAnimation;
     28 import com.android.messaging.datamodel.data.ConversationMessageBubbleData;
     29 import com.android.messaging.datamodel.data.ConversationMessageData;
     30 import com.android.messaging.util.UiUtils;
     31 
     32 /**
     33  * Shows the message bubble for one conversation message. It is able to animate size changes
     34  * by morphing when the message content changes size.
     35  */
     36 // TODO: Move functionality from ConversationMessageView into this class as appropriate
     37 public class ConversationMessageBubbleView extends LinearLayout {
     38     private int mIntrinsicWidth;
     39     private int mMorphedWidth;
     40     private ObjectAnimator mAnimator;
     41     private boolean mShouldAnimateWidthChange;
     42     private final ConversationMessageBubbleData mData;
     43     private int mRunningStartWidth;
     44     private ViewGroup mBubbleBackground;
     45 
     46     public ConversationMessageBubbleView(final Context context, final AttributeSet attrs) {
     47         super(context, attrs);
     48         mData = new ConversationMessageBubbleData();
     49     }
     50 
     51     @Override
     52     protected void onFinishInflate() {
     53         super.onFinishInflate();
     54         mBubbleBackground = (ViewGroup) findViewById(R.id.message_text_and_info);
     55     }
     56 
     57     @Override
     58     protected void onMeasure(final int widthMeasureSpec, final int heightMeasureSpec) {
     59         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
     60 
     61         final int newIntrinsicWidth = getMeasuredWidth();
     62         if (mIntrinsicWidth == 0 && newIntrinsicWidth != mIntrinsicWidth) {
     63             if (mShouldAnimateWidthChange) {
     64                 kickOffMorphAnimation(mIntrinsicWidth, newIntrinsicWidth);
     65             }
     66             mIntrinsicWidth = newIntrinsicWidth;
     67         }
     68 
     69         if (mMorphedWidth > 0) {
     70             mBubbleBackground.getLayoutParams().width = mMorphedWidth;
     71         } else {
     72             mBubbleBackground.getLayoutParams().width = LayoutParams.WRAP_CONTENT;
     73         }
     74         mBubbleBackground.requestLayout();
     75     }
     76 
     77     @VisibleForAnimation
     78     public void setMorphWidth(final int width) {
     79         mMorphedWidth = width;
     80         requestLayout();
     81     }
     82 
     83     public void bind(final ConversationMessageData data) {
     84         final boolean changed = mData.bind(data);
     85         // Animate width change only when we are binding to the same message, so that we may
     86         // animate view size changes on the same message bubble due to things like status text
     87         // change.
     88         // Don't animate width change when the bubble contains attachments. Width animation is
     89         // only suitable for text-only messages (where the bubble size change due to status or
     90         // time stamp changes).
     91         mShouldAnimateWidthChange = !changed && !data.hasAttachments();
     92         if (mAnimator == null) {
     93             mMorphedWidth = 0;
     94         }
     95     }
     96 
     97     public void kickOffMorphAnimation(final int oldWidth, final int newWidth) {
     98         if (mAnimator != null) {
     99             mAnimator.setIntValues(mRunningStartWidth, newWidth);
    100             return;
    101         }
    102         mRunningStartWidth = oldWidth;
    103         mAnimator = ObjectAnimator.ofInt(this, "morphWidth", oldWidth, newWidth);
    104         mAnimator.setDuration(UiUtils.MEDIAPICKER_TRANSITION_DURATION);
    105         mAnimator.addListener(new AnimatorListener() {
    106             @Override
    107             public void onAnimationStart(Animator animator) {
    108             }
    109 
    110             @Override
    111             public void onAnimationEnd(Animator animator) {
    112                 mAnimator = null;
    113                 mMorphedWidth = 0;
    114                 // Allow the bubble to resize if, for example, the status text changed during
    115                 // the animation.  This will snap to the bigger size if needed.  This is intentional
    116                 // as animating immediately after looks really bad and switching layout params
    117                 // during the original animation does not achieve the desired effect.
    118                 mBubbleBackground.getLayoutParams().width = LayoutParams.WRAP_CONTENT;
    119                 mBubbleBackground.requestLayout();
    120             }
    121 
    122             @Override
    123             public void onAnimationCancel(Animator animator) {
    124             }
    125 
    126             @Override
    127             public void onAnimationRepeat(Animator animator) {
    128             }
    129         });
    130         mAnimator.start();
    131     }
    132 }
    133