ExpandingEntryCardView.java revision c205cf1d4db6a85f52175af0add8852d5e1f8605
12d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos/*
22d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos * Copyright (C) 2014 The Android Open Source Project
32d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos *
42d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos * Licensed under the Apache License, Version 2.0 (the "License");
52d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos * you may not use this file except in compliance with the License.
62d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos * You may obtain a copy of the License at
72d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos *
82d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos *      http://www.apache.org/licenses/LICENSE-2.0
92d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos *
102d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos * Unless required by applicable law or agreed to in writing, software
112d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos * distributed under the License is distributed on an "AS IS" BASIS,
122d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
132d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos * See the License for the specific language governing permissions and
142d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos * limitations under the License.
152d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos */
162d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulospackage com.android.contacts.quickcontact;
172d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
18c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulosimport android.animation.ObjectAnimator;
192d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport android.content.Context;
202d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport android.content.Intent;
212d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport android.content.res.Resources;
227b0b0ce616c6c2fa149918c112128388712f5657Paul Soulosimport android.graphics.ColorFilter;
23dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulosimport android.graphics.Rect;
242d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport android.graphics.drawable.Drawable;
25ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulosimport android.support.v7.widget.CardView;
262d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport android.text.TextUtils;
270cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulosimport android.transition.ChangeBounds;
280cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulosimport android.transition.ChangeScroll;
290cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulosimport android.transition.Fade;
300cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulosimport android.transition.Transition;
310cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulosimport android.transition.Transition.TransitionListener;
320cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulosimport android.transition.TransitionManager;
330cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulosimport android.transition.TransitionSet;
342d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport android.util.AttributeSet;
352d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport android.util.Log;
362d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport android.view.LayoutInflater;
37dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulosimport android.view.TouchDelegate;
382d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport android.view.View;
392d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport android.view.ViewGroup;
40ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulosimport android.widget.FrameLayout;
412d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport android.widget.ImageView;
422d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport android.widget.LinearLayout;
434b943553afdb7286b33e4bc2481431e816c57967Paul Soulosimport android.widget.RelativeLayout;
442d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport android.widget.TextView;
452d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
460cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulosimport com.android.contacts.R;
470cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
482d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport java.util.ArrayList;
492d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport java.util.List;
502d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
512d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos/**
522d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos * Display entries in a LinearLayout that can be expanded to show all entries.
532d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos */
54ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulospublic class ExpandingEntryCardView extends CardView {
552d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
562d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private static final String TAG = "ExpandingEntryCardView";
570cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos    private static final int DURATION_EXPAND_ANIMATION_FADE_IN = 200;
580cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos    private static final int DELAY_EXPAND_ANIMATION_FADE_IN = 100;
590cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
600cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos    public static final int DURATION_EXPAND_ANIMATION_CHANGE_BOUNDS = 300;
610cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos    public static final int DURATION_COLLAPSE_ANIMATION_CHANGE_BOUNDS = 300;
622d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
632d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    /**
642d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     * Entry data.
652d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     */
662d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    public static final class Entry {
672d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
68ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos        private final int mViewId;
692d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        private final Drawable mIcon;
702d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        private final String mHeader;
712d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        private final String mSubHeader;
722d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        private final Drawable mSubHeaderIcon;
732d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        private final String mText;
742d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        private final Drawable mTextIcon;
752d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        private final Intent mIntent;
76dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        private final Drawable mAlternateIcon;
77dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        private final Intent mAlternateIntent;
78dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        private final String mAlternateContentDescription;
7948ebbaafcf467c072e4477c98ef2faba1c65af7ePaul Soulos        private final boolean mShouldApplyColor;
802d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        private final boolean mIsEditable;
812d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
82ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos        public Entry(int viewId, Drawable icon, String header, String subHeader, String text,
83dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                Intent intent, Drawable alternateIcon, Intent alternateIntent,
84dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                String alternateContentDescription, boolean shouldApplyColor,
85dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                boolean isEditable) {
86dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            this(viewId, icon, header, subHeader, null, text, null, intent, alternateIcon,
87dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                    alternateIntent, alternateContentDescription, shouldApplyColor, isEditable);
882d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
892d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
90ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos        public Entry(int viewId, Drawable mainIcon, String header, String subHeader,
912d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos                Drawable subHeaderIcon, String text, Drawable textIcon, Intent intent,
92dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                Drawable alternateIcon, Intent alternateIntent, String alternateContentDescription,
9348ebbaafcf467c072e4477c98ef2faba1c65af7ePaul Soulos                boolean shouldApplyColor, boolean isEditable) {
94ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos            mViewId = viewId;
952d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            mIcon = mainIcon;
962d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            mHeader = header;
972d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            mSubHeader = subHeader;
982d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            mSubHeaderIcon = subHeaderIcon;
992d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            mText = text;
1002d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            mTextIcon = textIcon;
1012d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            mIntent = intent;
102dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            mAlternateIcon = alternateIcon;
103dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            mAlternateIntent = alternateIntent;
104dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            mAlternateContentDescription = alternateContentDescription;
10548ebbaafcf467c072e4477c98ef2faba1c65af7ePaul Soulos            mShouldApplyColor = shouldApplyColor;
1062d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            mIsEditable = isEditable;
1072d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
1082d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
1092d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        Drawable getIcon() {
1102d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            return mIcon;
1112d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
1122d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
1132d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        String getHeader() {
1142d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            return mHeader;
1152d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
1162d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
1172d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        String getSubHeader() {
1182d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            return mSubHeader;
1192d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
1202d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
1212d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        Drawable getSubHeaderIcon() {
1222d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            return mSubHeaderIcon;
1232d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
1242d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
1252d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        public String getText() {
1262d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            return mText;
1272d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
1282d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
1292d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        Drawable getTextIcon() {
1302d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            return mTextIcon;
1312d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
1322d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
1332d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        Intent getIntent() {
1342d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            return mIntent;
1352d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
1362d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
137dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        Drawable getAlternateIcon() {
138dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            return mAlternateIcon;
139dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        }
140dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos
141dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        Intent getAlternateIntent() {
142dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            return mAlternateIntent;
143dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        }
144dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos
145dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        String getAlternateContentDescription() {
146dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            return mAlternateContentDescription;
147dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        }
148dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos
14948ebbaafcf467c072e4477c98ef2faba1c65af7ePaul Soulos        boolean shouldApplyColor() {
15048ebbaafcf467c072e4477c98ef2faba1c65af7ePaul Soulos            return mShouldApplyColor;
15148ebbaafcf467c072e4477c98ef2faba1c65af7ePaul Soulos        }
15248ebbaafcf467c072e4477c98ef2faba1c65af7ePaul Soulos
1532d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        boolean isEditable() {
1542d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            return mIsEditable;
1552d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
156ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos
157ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos        int getViewId() {
158ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos            return mViewId;
159ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos        }
1602d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
1612d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
162e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell    public interface ExpandingEntryCardViewListener {
163e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell        void onCollapse(int heightDelta);
1640cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        void onExpand(int heightDelta);
165e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell    }
166e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell
1672d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private View mExpandCollapseButton;
1682d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private TextView mExpandCollapseTextView;
1692d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private TextView mTitleTextView;
1702d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private CharSequence mExpandButtonText;
1712d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private CharSequence mCollapseButtonText;
1722d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private OnClickListener mOnClickListener;
1732d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private boolean mIsExpanded = false;
1742d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private int mCollapsedEntriesCount;
175e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell    private ExpandingEntryCardViewListener mListener;
17660e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos    private List<List<Entry>> mEntries;
17760e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos    private int mNumEntries = 0;
17860e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos    private boolean mAllEntriesInflated = false;
17960e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos    private List<List<View>> mEntryViews;
1802d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private LinearLayout mEntriesViewGroup;
181c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos    private final ImageView mExpandCollapseArrow;
1822d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private int mThemeColor;
1837b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos    private ColorFilter mThemeColorFilter;
18489966b4ed8cc9d385e5ac6b4a7e9e08ada387eb0Paul Soulos    private boolean mIsAlwaysExpanded;
1850cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos    /** The ViewGroup to run the expand/collapse animation on */
1860cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos    private ViewGroup mAnimationViewGroup;
1876b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos    private LinearLayout mBadgeContainer;
1886b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos    private final List<ImageView> mBadges;
189ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos    private LinearLayout mContainer;
1902d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
1912d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private final OnClickListener mExpandCollapseButtonListener = new OnClickListener() {
1922d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        @Override
1932d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        public void onClick(View v) {
1942d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            if (mIsExpanded) {
1952d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos                collapse();
1962d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            } else {
1972d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos                expand();
1982d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            }
1992d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
2002d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    };
2012d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
2022d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    public ExpandingEntryCardView(Context context) {
2030d49d81a3df2eea40dfe57570767c7661463f2dcBrian Attwell        this(context, null);
2042d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
2052d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
2062d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    public ExpandingEntryCardView(Context context, AttributeSet attrs) {
2072d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        super(context, attrs);
2082d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        LayoutInflater inflater = LayoutInflater.from(context);
2092d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        View expandingEntryCardView = inflater.inflate(R.layout.expanding_entry_card_view, this);
2102d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        mEntriesViewGroup = (LinearLayout)
2112d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos                expandingEntryCardView.findViewById(R.id.content_area_linear_layout);
2122d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        mTitleTextView = (TextView) expandingEntryCardView.findViewById(R.id.title);
213ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos        mContainer = (LinearLayout) expandingEntryCardView.findViewById(R.id.container);
2147b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos
2157b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos        mExpandCollapseButton = inflater.inflate(
2167b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos                R.layout.quickcontact_expanding_entry_card_button, this, false);
2177b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos        mExpandCollapseTextView = (TextView) mExpandCollapseButton.findViewById(R.id.text);
218c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos        mExpandCollapseArrow = (ImageView) mExpandCollapseButton.findViewById(R.id.arrow);
2197b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos        mExpandCollapseButton.setOnClickListener(mExpandCollapseButtonListener);
2206b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos        mBadgeContainer = (LinearLayout) mExpandCollapseButton.findViewById(R.id.badge_container);
2217b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos
2226b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos        mBadges = new ArrayList<ImageView>();
2232d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
2242d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
2252d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    /**
2262d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     * Sets the Entry list to display.
2272d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     *
2282d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     * @param entries The Entry list to display.
2292d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     */
23060e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos    public void initialize(List<List<Entry>> entries, int numInitialVisibleEntries,
23189966b4ed8cc9d385e5ac6b4a7e9e08ada387eb0Paul Soulos            boolean isExpanded, boolean isAlwaysExpanded,
2320cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            ExpandingEntryCardViewListener listener, ViewGroup animationViewGroup) {
2332d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        LayoutInflater layoutInflater = LayoutInflater.from(getContext());
2342d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        mIsExpanded = isExpanded;
23589966b4ed8cc9d385e5ac6b4a7e9e08ada387eb0Paul Soulos        mIsAlwaysExpanded = isAlwaysExpanded;
23689966b4ed8cc9d385e5ac6b4a7e9e08ada387eb0Paul Soulos        // If isAlwaysExpanded is true, mIsExpanded should be true
23789966b4ed8cc9d385e5ac6b4a7e9e08ada387eb0Paul Soulos        mIsExpanded |= mIsAlwaysExpanded;
23860e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos        mEntryViews = new ArrayList<List<View>>(entries.size());
2390d49d81a3df2eea40dfe57570767c7661463f2dcBrian Attwell        mEntries = entries;
2406095369885edcca566a812b551886e29c7ff8039Brian Attwell        mNumEntries = 0;
2416095369885edcca566a812b551886e29c7ff8039Brian Attwell        mAllEntriesInflated = false;
24260e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos        for (List<Entry> entryList : mEntries) {
24360e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            mNumEntries += entryList.size();
24460e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            mEntryViews.add(new ArrayList<View>());
24560e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos        }
24660e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos        mCollapsedEntriesCount = Math.min(numInitialVisibleEntries, mNumEntries);
24760e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos        // Only show the head of each entry list if the initial visible number falls between the
24860e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos        // number of lists and the total number of entries
24960e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos        if (mCollapsedEntriesCount > mEntries.size()) {
25060e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            mCollapsedEntriesCount = mEntries.size();
25160e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos        }
252e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell        mListener = listener;
2530cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        mAnimationViewGroup = animationViewGroup;
2540d49d81a3df2eea40dfe57570767c7661463f2dcBrian Attwell
2557b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos        if (mIsExpanded) {
256c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos            updateExpandCollapseButton(getCollapseButtonText(), /* duration = */ 0);
25760e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            inflateAllEntries(layoutInflater);
2587b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos        } else {
259c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos            updateExpandCollapseButton(getExpandButtonText(), /* duration = */ 0);
26060e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            inflateInitialEntries(layoutInflater);
2612d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
2622d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        insertEntriesIntoViewGroup();
2637b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos        applyColor();
2642d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
2652d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
2662d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    /**
2672d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     * Sets the text for the expand button.
2682d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     *
2692d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     * @param expandButtonText The expand button text.
2702d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     */
2712d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    public void setExpandButtonText(CharSequence expandButtonText) {
2722d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        mExpandButtonText = expandButtonText;
2732d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        if (mExpandCollapseTextView != null && !mIsExpanded) {
2742d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            mExpandCollapseTextView.setText(expandButtonText);
2752d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
2762d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
2772d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
2782d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    /**
2792d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     * Sets the text for the expand button.
2802d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     *
2812d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     * @param expandButtonText The expand button text.
2822d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     */
2832d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    public void setCollapseButtonText(CharSequence expandButtonText) {
2842d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        mCollapseButtonText = expandButtonText;
2852d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        if (mExpandCollapseTextView != null && mIsExpanded) {
2862d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            mExpandCollapseTextView.setText(mCollapseButtonText);
2872d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
2882d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
2892d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
2902d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    @Override
2912d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    public void setOnClickListener(OnClickListener listener) {
2922d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        mOnClickListener = listener;
2932d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
2942d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
2952d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private void insertEntriesIntoViewGroup() {
2962d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        mEntriesViewGroup.removeAllViews();
29760e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos
2982d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        if (mIsExpanded) {
29960e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            for (List<View> viewList : mEntryViews) {
30097ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                if (viewList != mEntryViews.get(0)) {
30197ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                    addSeparator(viewList.get(0));
30297ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                }
30360e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos                for (View view : viewList) {
30460e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos                    addEntry(view);
30560e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos                }
30660e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            }
30760e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos        } else {
30860e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            for (int i = 0; i < mCollapsedEntriesCount; i++) {
30997ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                if (i > 0) {
31097ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                    addSeparator(mEntryViews.get(i).get(0));
31197ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                }
31260e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos                addEntry(mEntryViews.get(i).get(0));
3132d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            }
3142d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
3152d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
3162d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        removeView(mExpandCollapseButton);
31760e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos        if (mCollapsedEntriesCount < mNumEntries
31889966b4ed8cc9d385e5ac6b4a7e9e08ada387eb0Paul Soulos                && mExpandCollapseButton.getParent() == null && !mIsAlwaysExpanded) {
319ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos            mContainer.addView(mExpandCollapseButton, -1);
3202d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
3212d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
3222d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
3232d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private void addEntry(View entry) {
3242d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        mEntriesViewGroup.addView(entry);
3252d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
3262d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
32797ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos    private void addSeparator(View entry) {
3280cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        View separator = new View(getContext());
329ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos        Resources res = getResources();
330ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos
331ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos        separator.setBackgroundColor(res.getColor(
3320cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos                R.color.expanding_entry_card_item_separator_color));
333ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos        LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
334ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos                ViewGroup.LayoutParams.MATCH_PARENT,
335ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos                res.getDimensionPixelSize(R.dimen.expanding_entry_card_item_separator_height));
3360cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        // The separator is aligned with the text in the entry. This is offset by a default
3370cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        // margin. If there is an icon present, the icon's width and margin are added
338ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos        int marginStart = res.getDimensionPixelSize(
3390cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos                R.dimen.expanding_entry_card_item_padding_start);
3400cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        ImageView entryIcon = (ImageView) entry.findViewById(R.id.icon);
34197ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos        if (entryIcon.getVisibility() == View.VISIBLE) {
3420cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            int imageWidthAndMargin =
343ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos                    res.getDimensionPixelSize(R.dimen.expanding_entry_card_item_icon_width) +
344ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos                    res.getDimensionPixelSize(R.dimen.expanding_entry_card_item_image_spacing);
3450cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            marginStart += imageWidthAndMargin;
3460cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        }
34797ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos        layoutParams.setMarginStart(marginStart);
3480cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        separator.setLayoutParams(layoutParams);
34997ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos        mEntriesViewGroup.addView(separator);
3500cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos    }
3510cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
3522d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private CharSequence getExpandButtonText() {
3532d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        if (!TextUtils.isEmpty(mExpandButtonText)) {
3542d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            return mExpandButtonText;
3552d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        } else {
3562d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            // Default to "See more".
3572d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            return getResources().getText(R.string.expanding_entry_card_view_see_more);
3582d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
3592d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
3602d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
3612d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private CharSequence getCollapseButtonText() {
3622d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        if (!TextUtils.isEmpty(mCollapseButtonText)) {
3632d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            return mCollapseButtonText;
3642d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        } else {
3652d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            // Default to "See less".
3662d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            return getResources().getText(R.string.expanding_entry_card_view_see_less);
3672d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
3682d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
3692d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
3700d49d81a3df2eea40dfe57570767c7661463f2dcBrian Attwell    /**
37160e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos     * Inflates the initial entries to be shown.
3720d49d81a3df2eea40dfe57570767c7661463f2dcBrian Attwell     */
37360e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos    private void inflateInitialEntries(LayoutInflater layoutInflater) {
37460e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos        // If the number of collapsed entries equals total entries, inflate all
37560e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos        if (mCollapsedEntriesCount == mNumEntries) {
37660e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            inflateAllEntries(layoutInflater);
37760e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos        } else {
37860e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            // Otherwise inflate the top entry from each list
37960e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            for (int i = 0; i < mCollapsedEntriesCount; i++) {
38097ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                mEntryViews.get(i).add(createEntryView(layoutInflater, mEntries.get(i).get(0),
38197ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                        /* showIcon = */ View.VISIBLE));
38260e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            }
38360e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos        }
38460e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos    }
38560e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos
38660e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos    /**
38760e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos     * Inflates all entries.
38860e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos     */
38960e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos    private void inflateAllEntries(LayoutInflater layoutInflater) {
39060e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos        if (mAllEntriesInflated) {
39160e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            return;
39260e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos        }
39360e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos        for (int i = 0; i < mEntries.size(); i++) {
39460e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            List<Entry> entryList = mEntries.get(i);
39560e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            List<View> viewList = mEntryViews.get(i);
39660e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            for (int j = viewList.size(); j < entryList.size(); j++) {
39797ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                final int iconVisibility;
39897ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                final Entry entry = entryList.get(j);
39997ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                // If the entry does not have an icon, mark gone. Else if it has an icon, show
40097ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                // for the first Entry in the list only
40197ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                if (entry.getIcon() == null) {
40297ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                    iconVisibility = View.GONE;
40397ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                } else if (j == 0) {
40497ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                    iconVisibility = View.VISIBLE;
40597ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                } else {
40697ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                    iconVisibility = View.INVISIBLE;
40797ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                }
40897ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                viewList.add(createEntryView(layoutInflater, entry, iconVisibility));
40960e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            }
4102d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
41160e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos        mAllEntriesInflated = true;
4122d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
4132d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
4147b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos    public void setColorAndFilter(int color, ColorFilter colorFilter) {
4157b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos        mThemeColor = color;
4167b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos        mThemeColorFilter = colorFilter;
4177b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos        applyColor();
4187b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos    }
4197b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos
4206095369885edcca566a812b551886e29c7ff8039Brian Attwell    public void setEntryHeaderColor(int color) {
4216095369885edcca566a812b551886e29c7ff8039Brian Attwell        if (mEntries != null) {
4226095369885edcca566a812b551886e29c7ff8039Brian Attwell            for (List<View> entryList : mEntryViews) {
4236095369885edcca566a812b551886e29c7ff8039Brian Attwell                for (View entryView : entryList) {
4246095369885edcca566a812b551886e29c7ff8039Brian Attwell                    TextView header = (TextView) entryView.findViewById(R.id.header);
4256095369885edcca566a812b551886e29c7ff8039Brian Attwell                    if (header != null) {
4266095369885edcca566a812b551886e29c7ff8039Brian Attwell                        header.setTextColor(color);
4276095369885edcca566a812b551886e29c7ff8039Brian Attwell                    }
4286095369885edcca566a812b551886e29c7ff8039Brian Attwell                }
4296095369885edcca566a812b551886e29c7ff8039Brian Attwell            }
4306095369885edcca566a812b551886e29c7ff8039Brian Attwell        }
4316095369885edcca566a812b551886e29c7ff8039Brian Attwell    }
4326095369885edcca566a812b551886e29c7ff8039Brian Attwell
4337b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos    /**
4347b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos     * The ColorFilter is passed in along with the color so that a new one only needs to be created
4357b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos     * once for the entire activity.
4367b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos     * 1. Title
4377b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos     * 2. Entry icons
4387b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos     * 3. Expand/Collapse Text
4397b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos     * 4. Expand/Collapse Button
4407b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos     */
4417b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos    public void applyColor() {
4427b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos        if (mThemeColor != 0 && mThemeColorFilter != null) {
4437b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos            // Title
4447b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos            if (mTitleTextView != null) {
4457b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos                mTitleTextView.setTextColor(mThemeColor);
4467b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos            }
4477b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos
4487b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos            // Entry icons
4497b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos            if (mEntries != null) {
45060e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos                for (List<Entry> entryList : mEntries) {
45160e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos                    for (Entry entry : entryList) {
45248ebbaafcf467c072e4477c98ef2faba1c65af7ePaul Soulos                        if (entry.shouldApplyColor()) {
45348ebbaafcf467c072e4477c98ef2faba1c65af7ePaul Soulos                            Drawable icon = entry.getIcon();
45448ebbaafcf467c072e4477c98ef2faba1c65af7ePaul Soulos                            if (icon != null) {
45548ebbaafcf467c072e4477c98ef2faba1c65af7ePaul Soulos                                icon.setColorFilter(mThemeColorFilter);
45648ebbaafcf467c072e4477c98ef2faba1c65af7ePaul Soulos                            }
45760e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos                        }
458dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                        Drawable alternateIcon = entry.getAlternateIcon();
459dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                        if (alternateIcon != null) {
460dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                            alternateIcon.setColorFilter(mThemeColorFilter);
461dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                        }
462eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                    }
4637b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos                }
4647b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos            }
4657b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos
4667b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos            // Expand/Collapse
4677b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos            mExpandCollapseTextView.setTextColor(mThemeColor);
468c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos            mExpandCollapseArrow.setColorFilter(mThemeColorFilter);
4697b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos        }
4707b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos    }
4717b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos
47297ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos    private View createEntryView(LayoutInflater layoutInflater, Entry entry, int iconVisibility) {
473dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        final View view = layoutInflater.inflate(
4742d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos                R.layout.expanding_entry_card_item, this, false);
4752d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
476ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos        view.setId(entry.getViewId());
477ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos
478dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        final ImageView icon = (ImageView) view.findViewById(R.id.icon);
47997ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos        icon.setVisibility(iconVisibility);
480eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        if (entry.getIcon() != null) {
481eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            icon.setImageDrawable(entry.getIcon());
482eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        }
483dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        final TextView header = (TextView) view.findViewById(R.id.header);
48403ece86bc2bda7f29aa2f8f2111035e4c6c6b871Paul Soulos        if (!TextUtils.isEmpty(entry.getHeader())) {
4852d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            header.setText(entry.getHeader());
4862d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        } else {
4872d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            header.setVisibility(View.GONE);
4882d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
4892d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
490dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        final TextView subHeader = (TextView) view.findViewById(R.id.sub_header);
49103ece86bc2bda7f29aa2f8f2111035e4c6c6b871Paul Soulos        if (!TextUtils.isEmpty(entry.getSubHeader())) {
4922d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            subHeader.setText(entry.getSubHeader());
4932d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        } else {
4942d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            subHeader.setVisibility(View.GONE);
4952d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
4962d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
497dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        final ImageView subHeaderIcon = (ImageView) view.findViewById(R.id.icon_sub_header);
4982d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        if (entry.getSubHeaderIcon() != null) {
4992d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            subHeaderIcon.setImageDrawable(entry.getSubHeaderIcon());
5002d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        } else {
5012d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            subHeaderIcon.setVisibility(View.GONE);
5022d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
5032d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
504dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        final TextView text = (TextView) view.findViewById(R.id.text);
50503ece86bc2bda7f29aa2f8f2111035e4c6c6b871Paul Soulos        if (!TextUtils.isEmpty(entry.getText())) {
5062d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            text.setText(entry.getText());
5072d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        } else {
5082d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            text.setVisibility(View.GONE);
5092d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
5102d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
511dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        final ImageView textIcon = (ImageView) view.findViewById(R.id.icon_text);
5122d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        if (entry.getTextIcon() != null) {
5132d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            textIcon.setImageDrawable(entry.getTextIcon());
5142d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        } else {
5152d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            textIcon.setVisibility(View.GONE);
5162d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
5172d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
5182d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        if (entry.getIntent() != null) {
5197d22b94ce50f7a65dd89d4533f2aa3a3392e7972Paul Soulos            view.setOnClickListener(mOnClickListener);
5207d22b94ce50f7a65dd89d4533f2aa3a3392e7972Paul Soulos            view.setTag(entry.getIntent());
5212d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
5222d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
523ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos        // If only the header is visible, add a top margin to match icon's top margin.
524ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos        // Also increase the space below the header for visual comfort.
5254b943553afdb7286b33e4bc2481431e816c57967Paul Soulos        if (header.getVisibility() == View.VISIBLE && subHeader.getVisibility() == View.GONE &&
5264b943553afdb7286b33e4bc2481431e816c57967Paul Soulos                text.getVisibility() == View.GONE) {
5274b943553afdb7286b33e4bc2481431e816c57967Paul Soulos            RelativeLayout.LayoutParams headerLayoutParams =
5284b943553afdb7286b33e4bc2481431e816c57967Paul Soulos                    (RelativeLayout.LayoutParams) header.getLayoutParams();
5294b943553afdb7286b33e4bc2481431e816c57967Paul Soulos            headerLayoutParams.topMargin = (int) (getResources().getDimension(
530ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos                    R.dimen.expanding_entry_card_item_header_only_margin_top));
531ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos            headerLayoutParams.bottomMargin += (int) (getResources().getDimension(
532ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos                    R.dimen.expanding_entry_card_item_header_only_margin_bottom));
5334b943553afdb7286b33e4bc2481431e816c57967Paul Soulos            header.setLayoutParams(headerLayoutParams);
5344b943553afdb7286b33e4bc2481431e816c57967Paul Soulos        }
5354b943553afdb7286b33e4bc2481431e816c57967Paul Soulos
536dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        final ImageView alternateIcon = (ImageView) view.findViewById(R.id.icon_alternate);
537dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        if (entry.getAlternateIcon() != null && entry.getAlternateIntent() != null) {
538dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            alternateIcon.setImageDrawable(entry.getAlternateIcon());
539dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            alternateIcon.setOnClickListener(mOnClickListener);
540dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            alternateIcon.setTag(entry.getAlternateIntent());
541dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            alternateIcon.setId(entry.getViewId());
542dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            alternateIcon.setVisibility(View.VISIBLE);
543dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            alternateIcon.setContentDescription(entry.getAlternateContentDescription());
544dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos
545891bd2bad8de331a089466777cd054674261a969Paul Soulos            // Expand the clickable area for alternate icon to be top to bottom and to end edge
546dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            // of the entry view
547dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            view.post(new Runnable() {
548dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                @Override
549dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                public void run() {
550dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                    final Rect alternateIconRect = new Rect();
551dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                    alternateIcon.getHitRect(alternateIconRect);
552891bd2bad8de331a089466777cd054674261a969Paul Soulos
553891bd2bad8de331a089466777cd054674261a969Paul Soulos                    alternateIconRect.bottom = view.getHeight();
554891bd2bad8de331a089466777cd054674261a969Paul Soulos                    alternateIconRect.top = 0;
555714455bba22b99d168a2e864dfbc74a6e30dfdb6Paul Soulos                    if (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
556891bd2bad8de331a089466777cd054674261a969Paul Soulos                        alternateIconRect.left = 0;
557714455bba22b99d168a2e864dfbc74a6e30dfdb6Paul Soulos                    } else {
558891bd2bad8de331a089466777cd054674261a969Paul Soulos                        alternateIconRect.right = view.getWidth();
559714455bba22b99d168a2e864dfbc74a6e30dfdb6Paul Soulos                    }
560dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                    final TouchDelegate touchDelegate =
561dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                            new TouchDelegate(alternateIconRect, alternateIcon);
562dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                    view.setTouchDelegate(touchDelegate);
563dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                }
564dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            });
565dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        }
566dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos
567ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos        // Decrease margin for entries that have an invisible icon
568ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos        if (iconVisibility == View.INVISIBLE) {
569ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos            view.setPaddingRelative(view.getPaddingStart(), 0, view.getPaddingEnd(),
570ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos                    view.getPaddingBottom());
571ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos        }
572ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos
5732d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        return view;
5742d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
5752d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
576c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos    private void updateExpandCollapseButton(CharSequence buttonText, long duration) {
577c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos        if (mIsExpanded) {
578c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos            final ObjectAnimator animator = ObjectAnimator.ofFloat(mExpandCollapseArrow,
579c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos                    "rotation", 180);
580c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos            animator.setDuration(duration);
581c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos            animator.start();
5822d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        } else {
583c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos            final ObjectAnimator animator = ObjectAnimator.ofFloat(mExpandCollapseArrow,
584c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos                    "rotation", 0);
585c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos            animator.setDuration(duration);
586c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos            animator.start();
5872d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
588c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos        updateBadges();
589c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos
5902d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        mExpandCollapseTextView.setText(buttonText);
5912d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
5922d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
5936b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos    private void updateBadges() {
5946b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos        if (mIsExpanded) {
5956b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos            mBadgeContainer.removeAllViews();
5966b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos        } else {
5976b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos            // Inflate badges if not yet created
5986b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos            if (mBadges.size() < mEntries.size() - mCollapsedEntriesCount) {
5996b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos                for (int i = mCollapsedEntriesCount; i < mEntries.size(); i++) {
6006b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos                    Drawable badgeDrawable = mEntries.get(i).get(0).getIcon();
6016b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos                    if (badgeDrawable != null) {
6026b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos                        ImageView badgeView = new ImageView(getContext());
6036b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos                        LinearLayout.LayoutParams badgeViewParams = new LinearLayout.LayoutParams(
6046b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos                                (int) getResources().getDimension(
6056b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos                                        R.dimen.expanding_entry_card_item_icon_width),
6066b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos                                (int) getResources().getDimension(
6076b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos                                        R.dimen.expanding_entry_card_item_icon_height));
6086b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos                        badgeViewParams.setMarginEnd((int) getResources().getDimension(
6096b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos                                R.dimen.expanding_entry_card_badge_separator_margin));
6106b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos                        badgeView.setLayoutParams(badgeViewParams);
6116b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos                        badgeView.setImageDrawable(badgeDrawable);
6126b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos                        mBadges.add(badgeView);
6136b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos                    }
6146b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos                }
6156b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos            }
6166b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos            mBadgeContainer.removeAllViews();
6176b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos            for (ImageView badge : mBadges) {
6186b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos                mBadgeContainer.addView(badge);
6196b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos            }
6206b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos        }
6216b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos    }
6226b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos
6232d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private void expand() {
6240cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        ChangeBounds boundsTransition = new ChangeBounds();
6250cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        boundsTransition.setDuration(DURATION_EXPAND_ANIMATION_CHANGE_BOUNDS);
6260cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
6270cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        Fade fadeIn = new Fade(Fade.IN);
6280cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        fadeIn.setDuration(DURATION_EXPAND_ANIMATION_FADE_IN);
6290cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        fadeIn.setStartDelay(DELAY_EXPAND_ANIMATION_FADE_IN);
6300cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
6310cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        TransitionSet transitionSet = new TransitionSet();
6320cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        transitionSet.addTransition(boundsTransition);
6330cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        transitionSet.addTransition(fadeIn);
6340cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
6350cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        final ViewGroup transitionViewContainer = mAnimationViewGroup == null ?
6360cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos                this : mAnimationViewGroup;
6370cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
6380cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        transitionSet.addListener(new TransitionListener() {
6390cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            @Override
6400cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            public void onTransitionStart(Transition transition) {
6410cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos                // The listener is used to turn off suppressing, the proper delta is not necessary
6420cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos                mListener.onExpand(0);
6430cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            }
6440cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
6450cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            @Override
6460cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            public void onTransitionEnd(Transition transition) {
6470cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            }
6480cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
6490cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            @Override
6500cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            public void onTransitionCancel(Transition transition) {
6510cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            }
6520cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
6530cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            @Override
6540cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            public void onTransitionPause(Transition transition) {
6550cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            }
6560cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
6570cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            @Override
6580cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            public void onTransitionResume(Transition transition) {
6590cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            }
6600cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        });
6610cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
6620cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        TransitionManager.beginDelayedTransition(transitionViewContainer, transitionSet);
6632d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
6642d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        mIsExpanded = true;
6650d49d81a3df2eea40dfe57570767c7661463f2dcBrian Attwell        // In order to insert new entries, we may need to inflate them for the first time
66660e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos        inflateAllEntries(LayoutInflater.from(getContext()));
6672d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        insertEntriesIntoViewGroup();
668c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos        updateExpandCollapseButton(getCollapseButtonText(),
669c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos                DURATION_EXPAND_ANIMATION_CHANGE_BOUNDS);
6702d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
6712d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
6722d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private void collapse() {
6730cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        final int startingHeight = mEntriesViewGroup.getMeasuredHeight();
6742d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        mIsExpanded = false;
675c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos        updateExpandCollapseButton(getExpandButtonText(),
676c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos                DURATION_COLLAPSE_ANIMATION_CHANGE_BOUNDS);
6772d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
6780cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        final ChangeBounds boundsTransition = new ChangeBounds();
6790cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        boundsTransition.setDuration(DURATION_COLLAPSE_ANIMATION_CHANGE_BOUNDS);
6802d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
6810cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        final ChangeScroll scrollTransition = new ChangeScroll();
6820cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        scrollTransition.setDuration(DURATION_COLLAPSE_ANIMATION_CHANGE_BOUNDS);
6830cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
6840cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        TransitionSet transitionSet = new TransitionSet();
6850cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        transitionSet.addTransition(boundsTransition);
6860cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        transitionSet.addTransition(scrollTransition);
6870cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
6880cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        final ViewGroup transitionViewContainer = mAnimationViewGroup == null ?
6890cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos                this : mAnimationViewGroup;
6900cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
6910cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        boundsTransition.addListener(new TransitionListener() {
6922d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            @Override
6930cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            public void onTransitionStart(Transition transition) {
6940cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos                /*
6950cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos                 * onTransitionStart is called after the view hierarchy has been changed but before
6960cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos                 * the animation begins.
6970cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos                 */
6980cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos                int finishingHeight = mEntriesViewGroup.getMeasuredHeight();
6990cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos                mListener.onCollapse(startingHeight - finishingHeight);
7002d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            }
7010cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
7020cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            @Override
7030cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            public void onTransitionEnd(Transition transition) {
7040cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            }
7050cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
7062d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            @Override
7070cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            public void onTransitionCancel(Transition transition) {
7080cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            }
7090cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
7100cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            @Override
7110cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            public void onTransitionPause(Transition transition) {
7120cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            }
7130cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
7140cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            @Override
7150cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            public void onTransitionResume(Transition transition) {
7162d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            }
7172d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        });
7180cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
7190cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        TransitionManager.beginDelayedTransition(transitionViewContainer, transitionSet);
7200cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
7210cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        insertEntriesIntoViewGroup();
7222d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
7232d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
7242d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    /**
7252d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     * Returns whether the view is currently in its expanded state.
7262d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     */
7272d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    public boolean isExpanded() {
7282d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        return mIsExpanded;
7292d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
7302d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
7312d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    /**
7322d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     * Sets the title text of this ExpandingEntryCardView.
7332fa690807a94708384789b211965bfc75b5ac38ePaul Soulos     * @param title The title to set. A null title will result in the title being removed.
7342d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     */
7352d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    public void setTitle(String title) {
7362d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        if (mTitleTextView == null) {
7372d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            Log.e(TAG, "mTitleTextView is null");
7382d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
7392d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        if (title == null) {
7402fa690807a94708384789b211965bfc75b5ac38ePaul Soulos            mTitleTextView.setVisibility(View.GONE);
741f5cc63f9f25f8d75a524202d2bd4f7d388d787a8Paul Soulos            findViewById(R.id.title_separator).setVisibility(View.GONE);
7422d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
7432d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        mTitleTextView.setText(title);
7442fa690807a94708384789b211965bfc75b5ac38ePaul Soulos        mTitleTextView.setVisibility(View.VISIBLE);
745f5cc63f9f25f8d75a524202d2bd4f7d388d787a8Paul Soulos        findViewById(R.id.title_separator).setVisibility(View.VISIBLE);
7462d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
747eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
748eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    public boolean shouldShow() {
749eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        return mEntries != null && mEntries.size() > 0;
750eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    }
7512d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos}
752