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
18245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwellimport android.animation.Animator;
19245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwellimport android.animation.Animator.AnimatorListener;
20245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwellimport android.animation.AnimatorSet;
21c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulosimport android.animation.ObjectAnimator;
222d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport android.content.Context;
232d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport android.content.Intent;
242d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport android.content.res.Resources;
257b0b0ce616c6c2fa149918c112128388712f5657Paul Soulosimport android.graphics.ColorFilter;
26dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulosimport android.graphics.Rect;
272d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport android.graphics.drawable.Drawable;
28ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulosimport android.support.v7.widget.CardView;
297ce5352a70e8aaf120bf4f7bd05d595f46abb080Walter Jangimport android.text.Spannable;
302d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport android.text.TextUtils;
310cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulosimport android.transition.ChangeBounds;
320cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulosimport android.transition.Fade;
330cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulosimport android.transition.Transition;
340cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulosimport android.transition.Transition.TransitionListener;
350cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulosimport android.transition.TransitionManager;
360cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulosimport android.transition.TransitionSet;
372d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport android.util.AttributeSet;
382d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport android.util.Log;
39245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwellimport android.util.Property;
402a4207fb39330e840436215c896cde911489e111Paul Soulosimport android.view.ContextMenu.ContextMenuInfo;
412d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport android.view.LayoutInflater;
4248fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulosimport android.view.MotionEvent;
432d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport android.view.View;
4448fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulosimport android.view.ViewConfiguration;
452d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport android.view.ViewGroup;
462d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport android.widget.ImageView;
472d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport android.widget.LinearLayout;
48245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwellimport android.widget.LinearLayout.LayoutParams;
494b943553afdb7286b33e4bc2481431e816c57967Paul Soulosimport android.widget.RelativeLayout;
502d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport android.widget.TextView;
512d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
520cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulosimport com.android.contacts.R;
530cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
542d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport java.util.ArrayList;
552d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulosimport java.util.List;
562d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
572d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos/**
582d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos * Display entries in a LinearLayout that can be expanded to show all entries.
592d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos */
60ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulospublic class ExpandingEntryCardView extends CardView {
612d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
622d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private static final String TAG = "ExpandingEntryCardView";
630cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos    private static final int DURATION_EXPAND_ANIMATION_FADE_IN = 200;
64245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell    private static final int DURATION_COLLAPSE_ANIMATION_FADE_OUT = 75;
650cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos    private static final int DELAY_EXPAND_ANIMATION_FADE_IN = 100;
660cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
670cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos    public static final int DURATION_EXPAND_ANIMATION_CHANGE_BOUNDS = 300;
680cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos    public static final int DURATION_COLLAPSE_ANIMATION_CHANGE_BOUNDS = 300;
692d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
70245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell    private static final Property<View, Integer> VIEW_LAYOUT_HEIGHT_PROPERTY =
71245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell            new Property<View, Integer>(Integer.class, "height") {
72245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell                @Override
73245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell                public void set(View view, Integer height) {
74245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell                    LinearLayout.LayoutParams params = (LinearLayout.LayoutParams)
75245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell                            view.getLayoutParams();
76245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell                    params.height = height;
77245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell                    view.setLayoutParams(params);
78245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell                }
79245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell
80245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell                @Override
81245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell                public Integer get(View view) {
82245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell                    return view.getLayoutParams().height;
83245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell                }
84245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell            };
85245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell
862d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    /**
872d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     * Entry data.
882d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     */
892d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    public static final class Entry {
902d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
912ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos        private final int mId;
922d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        private final Drawable mIcon;
932d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        private final String mHeader;
942d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        private final String mSubHeader;
952d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        private final Drawable mSubHeaderIcon;
962d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        private final String mText;
972d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        private final Drawable mTextIcon;
987ce5352a70e8aaf120bf4f7bd05d595f46abb080Walter Jang        private Spannable mPrimaryContentDescription;
992d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        private final Intent mIntent;
100dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        private final Drawable mAlternateIcon;
101dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        private final Intent mAlternateIntent;
102dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        private final String mAlternateContentDescription;
10348ebbaafcf467c072e4477c98ef2faba1c65af7ePaul Soulos        private final boolean mShouldApplyColor;
1042d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        private final boolean mIsEditable;
1052a4207fb39330e840436215c896cde911489e111Paul Soulos        private final EntryContextMenuInfo mEntryContextMenuInfo;
10648fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        private final Drawable mThirdIcon;
10748fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        private final Intent mThirdIntent;
10848fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        private final String mThirdContentDescription;
10948290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos        private final int mIconResourceId;
1102d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
1112ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos        public Entry(int id, Drawable mainIcon, String header, String subHeader,
11223e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos                Drawable subHeaderIcon, String text, Drawable textIcon,
1137ce5352a70e8aaf120bf4f7bd05d595f46abb080Walter Jang                Spannable primaryContentDescription, Intent intent,
114dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                Drawable alternateIcon, Intent alternateIntent, String alternateContentDescription,
1152a4207fb39330e840436215c896cde911489e111Paul Soulos                boolean shouldApplyColor, boolean isEditable,
11648fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                EntryContextMenuInfo entryContextMenuInfo, Drawable thirdIcon, Intent thirdIntent,
11748290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                String thirdContentDescription, int iconResourceId) {
1182ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos            mId = id;
1192d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            mIcon = mainIcon;
1202d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            mHeader = header;
1212d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            mSubHeader = subHeader;
1222d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            mSubHeaderIcon = subHeaderIcon;
1232d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            mText = text;
1242d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            mTextIcon = textIcon;
12523e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos            mPrimaryContentDescription = primaryContentDescription;
1262d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            mIntent = intent;
127dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            mAlternateIcon = alternateIcon;
128dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            mAlternateIntent = alternateIntent;
129dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            mAlternateContentDescription = alternateContentDescription;
13048ebbaafcf467c072e4477c98ef2faba1c65af7ePaul Soulos            mShouldApplyColor = shouldApplyColor;
1312d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            mIsEditable = isEditable;
1322a4207fb39330e840436215c896cde911489e111Paul Soulos            mEntryContextMenuInfo = entryContextMenuInfo;
13348fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            mThirdIcon = thirdIcon;
13448fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            mThirdIntent = thirdIntent;
13548fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            mThirdContentDescription = thirdContentDescription;
13648290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos            mIconResourceId = iconResourceId;
1372d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
1382d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
1392d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        Drawable getIcon() {
1402d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            return mIcon;
1412d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
1422d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
1432d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        String getHeader() {
1442d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            return mHeader;
1452d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
1462d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
1472d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        String getSubHeader() {
1482d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            return mSubHeader;
1492d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
1502d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
1512d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        Drawable getSubHeaderIcon() {
1522d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            return mSubHeaderIcon;
1532d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
1542d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
1552d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        public String getText() {
1562d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            return mText;
1572d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
1582d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
1592d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        Drawable getTextIcon() {
1602d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            return mTextIcon;
1612d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
1622d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
1637ce5352a70e8aaf120bf4f7bd05d595f46abb080Walter Jang        Spannable getPrimaryContentDescription() {
16423e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos            return mPrimaryContentDescription;
16523e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos        }
16623e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos
1672d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        Intent getIntent() {
1682d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            return mIntent;
1692d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
1702d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
171dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        Drawable getAlternateIcon() {
172dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            return mAlternateIcon;
173dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        }
174dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos
175dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        Intent getAlternateIntent() {
176dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            return mAlternateIntent;
177dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        }
178dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos
179dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        String getAlternateContentDescription() {
180dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos            return mAlternateContentDescription;
181dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        }
182dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos
18348ebbaafcf467c072e4477c98ef2faba1c65af7ePaul Soulos        boolean shouldApplyColor() {
18448ebbaafcf467c072e4477c98ef2faba1c65af7ePaul Soulos            return mShouldApplyColor;
18548ebbaafcf467c072e4477c98ef2faba1c65af7ePaul Soulos        }
18648ebbaafcf467c072e4477c98ef2faba1c65af7ePaul Soulos
1872d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        boolean isEditable() {
1882d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            return mIsEditable;
1892d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
190ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos
1912ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos        int getId() {
1922ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos            return mId;
193ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos        }
1942a4207fb39330e840436215c896cde911489e111Paul Soulos
1952a4207fb39330e840436215c896cde911489e111Paul Soulos        EntryContextMenuInfo getEntryContextMenuInfo() {
1962a4207fb39330e840436215c896cde911489e111Paul Soulos            return mEntryContextMenuInfo;
1972a4207fb39330e840436215c896cde911489e111Paul Soulos        }
19848fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos
19948fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        Drawable getThirdIcon() {
20048fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            return mThirdIcon;
20148fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        }
20248fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos
20348fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        Intent getThirdIntent() {
20448fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            return mThirdIntent;
20548fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        }
20648fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos
20748fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        String getThirdContentDescription() {
20848fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            return mThirdContentDescription;
20948fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        }
21048290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos
21148290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos        int getIconResourceId() {
21248290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos            return mIconResourceId;
21348290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos        }
2142d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
2152d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
216e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell    public interface ExpandingEntryCardViewListener {
217e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell        void onCollapse(int heightDelta);
218245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell        void onExpand();
219245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell        void onExpandDone();
220e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell    }
221e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell
2222d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private View mExpandCollapseButton;
2232d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private TextView mExpandCollapseTextView;
2242d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private TextView mTitleTextView;
2252d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private CharSequence mExpandButtonText;
2262d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private CharSequence mCollapseButtonText;
2272d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private OnClickListener mOnClickListener;
2282a4207fb39330e840436215c896cde911489e111Paul Soulos    private OnCreateContextMenuListener mOnCreateContextMenuListener;
2292d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private boolean mIsExpanded = false;
230691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos    /**
231691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos     * The max number of entries to show in a collapsed card. If there are less entries passed in,
232691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos     * then they are all shown.
233691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos     */
2342d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private int mCollapsedEntriesCount;
235e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell    private ExpandingEntryCardViewListener mListener;
23660e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos    private List<List<Entry>> mEntries;
23760e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos    private int mNumEntries = 0;
23860e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos    private boolean mAllEntriesInflated = false;
23960e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos    private List<List<View>> mEntryViews;
2402d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private LinearLayout mEntriesViewGroup;
241c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos    private final ImageView mExpandCollapseArrow;
2422d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private int mThemeColor;
2437b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos    private ColorFilter mThemeColorFilter;
24405287bf0cea303b93802a629aa883fb6322ca342Brian Attwell    /**
24505287bf0cea303b93802a629aa883fb6322ca342Brian Attwell     * Whether to prioritize the first entry type. If prioritized, we should show at least two
24605287bf0cea303b93802a629aa883fb6322ca342Brian Attwell     * of this entry type.
24705287bf0cea303b93802a629aa883fb6322ca342Brian Attwell     */
24805287bf0cea303b93802a629aa883fb6322ca342Brian Attwell    private boolean mShowFirstEntryTypeTwice;
24989966b4ed8cc9d385e5ac6b4a7e9e08ada387eb0Paul Soulos    private boolean mIsAlwaysExpanded;
2500cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos    /** The ViewGroup to run the expand/collapse animation on */
2510cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos    private ViewGroup mAnimationViewGroup;
2526b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos    private LinearLayout mBadgeContainer;
2536b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos    private final List<ImageView> mBadges;
25448290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos    private final List<Integer> mBadgeIds;
25505287bf0cea303b93802a629aa883fb6322ca342Brian Attwell    private final int mDividerLineHeightPixels;
256cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos    /**
257cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos     * List to hold the separators. This saves us from reconstructing every expand/collapse and
258cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos     * provides a smoother animation.
259cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos     */
260cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos    private List<View> mSeparators;
261ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos    private LinearLayout mContainer;
2622d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
2632d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private final OnClickListener mExpandCollapseButtonListener = new OnClickListener() {
2642d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        @Override
2652d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        public void onClick(View v) {
2662d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            if (mIsExpanded) {
2672d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos                collapse();
2682d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            } else {
2692d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos                expand();
2702d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            }
2712d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
2722d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    };
2732d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
2742d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    public ExpandingEntryCardView(Context context) {
2750d49d81a3df2eea40dfe57570767c7661463f2dcBrian Attwell        this(context, null);
2762d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
2772d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
2782d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    public ExpandingEntryCardView(Context context, AttributeSet attrs) {
2792d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        super(context, attrs);
2802d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        LayoutInflater inflater = LayoutInflater.from(context);
2812d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        View expandingEntryCardView = inflater.inflate(R.layout.expanding_entry_card_view, this);
2822d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        mEntriesViewGroup = (LinearLayout)
2832d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos                expandingEntryCardView.findViewById(R.id.content_area_linear_layout);
2842d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        mTitleTextView = (TextView) expandingEntryCardView.findViewById(R.id.title);
285ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos        mContainer = (LinearLayout) expandingEntryCardView.findViewById(R.id.container);
2867b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos
2877b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos        mExpandCollapseButton = inflater.inflate(
2887b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos                R.layout.quickcontact_expanding_entry_card_button, this, false);
2897b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos        mExpandCollapseTextView = (TextView) mExpandCollapseButton.findViewById(R.id.text);
290c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos        mExpandCollapseArrow = (ImageView) mExpandCollapseButton.findViewById(R.id.arrow);
2917b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos        mExpandCollapseButton.setOnClickListener(mExpandCollapseButtonListener);
2926b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos        mBadgeContainer = (LinearLayout) mExpandCollapseButton.findViewById(R.id.badge_container);
29305287bf0cea303b93802a629aa883fb6322ca342Brian Attwell        mDividerLineHeightPixels = getResources()
29405287bf0cea303b93802a629aa883fb6322ca342Brian Attwell                .getDimensionPixelSize(R.dimen.divider_line_height);
2957b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos
2966b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos        mBadges = new ArrayList<ImageView>();
29748290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos        mBadgeIds = new ArrayList<Integer>();
2982d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
2992d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
30005287bf0cea303b93802a629aa883fb6322ca342Brian Attwell    public void initialize(List<List<Entry>> entries, int numInitialVisibleEntries,
30105287bf0cea303b93802a629aa883fb6322ca342Brian Attwell            boolean isExpanded, boolean isAlwaysExpanded, ExpandingEntryCardViewListener listener,
30205287bf0cea303b93802a629aa883fb6322ca342Brian Attwell            ViewGroup animationViewGroup) {
30305287bf0cea303b93802a629aa883fb6322ca342Brian Attwell        initialize(entries, numInitialVisibleEntries, isExpanded, isAlwaysExpanded,
30405287bf0cea303b93802a629aa883fb6322ca342Brian Attwell                listener, animationViewGroup, /* showFirstEntryTypeTwice = */ false);
30505287bf0cea303b93802a629aa883fb6322ca342Brian Attwell    }
30605287bf0cea303b93802a629aa883fb6322ca342Brian Attwell
3072d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    /**
3082d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     * Sets the Entry list to display.
3092d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     *
3102d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     * @param entries The Entry list to display.
3112d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     */
31260e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos    public void initialize(List<List<Entry>> entries, int numInitialVisibleEntries,
31389966b4ed8cc9d385e5ac6b4a7e9e08ada387eb0Paul Soulos            boolean isExpanded, boolean isAlwaysExpanded,
31405287bf0cea303b93802a629aa883fb6322ca342Brian Attwell            ExpandingEntryCardViewListener listener, ViewGroup animationViewGroup,
31505287bf0cea303b93802a629aa883fb6322ca342Brian Attwell            boolean showFirstEntryTypeTwice) {
3162d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        LayoutInflater layoutInflater = LayoutInflater.from(getContext());
3172d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        mIsExpanded = isExpanded;
31889966b4ed8cc9d385e5ac6b4a7e9e08ada387eb0Paul Soulos        mIsAlwaysExpanded = isAlwaysExpanded;
31989966b4ed8cc9d385e5ac6b4a7e9e08ada387eb0Paul Soulos        // If isAlwaysExpanded is true, mIsExpanded should be true
32089966b4ed8cc9d385e5ac6b4a7e9e08ada387eb0Paul Soulos        mIsExpanded |= mIsAlwaysExpanded;
32160e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos        mEntryViews = new ArrayList<List<View>>(entries.size());
3220d49d81a3df2eea40dfe57570767c7661463f2dcBrian Attwell        mEntries = entries;
3236095369885edcca566a812b551886e29c7ff8039Brian Attwell        mNumEntries = 0;
3246095369885edcca566a812b551886e29c7ff8039Brian Attwell        mAllEntriesInflated = false;
32505287bf0cea303b93802a629aa883fb6322ca342Brian Attwell        mShowFirstEntryTypeTwice = showFirstEntryTypeTwice;
32660e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos        for (List<Entry> entryList : mEntries) {
32760e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            mNumEntries += entryList.size();
32860e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            mEntryViews.add(new ArrayList<View>());
32960e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos        }
33060e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos        mCollapsedEntriesCount = Math.min(numInitialVisibleEntries, mNumEntries);
331cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos        // We need a separator between each list, but not after the last one
332cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos        if (entries.size() > 1) {
333cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos            mSeparators = new ArrayList<>(entries.size() - 1);
334cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos        }
335e8ce6ee1c5ab9f4f3dd11526337c70a8867647d9Brian Attwell        mListener = listener;
3360cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        mAnimationViewGroup = animationViewGroup;
3370d49d81a3df2eea40dfe57570767c7661463f2dcBrian Attwell
3387b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos        if (mIsExpanded) {
339c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos            updateExpandCollapseButton(getCollapseButtonText(), /* duration = */ 0);
34060e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            inflateAllEntries(layoutInflater);
3417b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos        } else {
342c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos            updateExpandCollapseButton(getExpandButtonText(), /* duration = */ 0);
34360e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            inflateInitialEntries(layoutInflater);
3442d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
3452d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        insertEntriesIntoViewGroup();
3467b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos        applyColor();
3472d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
3482d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
3492d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    /**
3502d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     * Sets the text for the expand button.
3512d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     *
3522d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     * @param expandButtonText The expand button text.
3532d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     */
3542d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    public void setExpandButtonText(CharSequence expandButtonText) {
3552d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        mExpandButtonText = expandButtonText;
3562d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        if (mExpandCollapseTextView != null && !mIsExpanded) {
3572d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            mExpandCollapseTextView.setText(expandButtonText);
3582d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
3592d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
3602d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
3612d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    /**
3622d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     * Sets the text for the expand button.
3632d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     *
3642d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     * @param expandButtonText The expand button text.
3652d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     */
3662d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    public void setCollapseButtonText(CharSequence expandButtonText) {
3672d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        mCollapseButtonText = expandButtonText;
3682d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        if (mExpandCollapseTextView != null && mIsExpanded) {
3692d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            mExpandCollapseTextView.setText(mCollapseButtonText);
3702d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
3712d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
3722d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
3732d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    @Override
3742d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    public void setOnClickListener(OnClickListener listener) {
3752d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        mOnClickListener = listener;
3762d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
3772d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
3782a4207fb39330e840436215c896cde911489e111Paul Soulos    @Override
3792a4207fb39330e840436215c896cde911489e111Paul Soulos    public void setOnCreateContextMenuListener (OnCreateContextMenuListener listener) {
3802a4207fb39330e840436215c896cde911489e111Paul Soulos        mOnCreateContextMenuListener = listener;
3812a4207fb39330e840436215c896cde911489e111Paul Soulos    }
3822a4207fb39330e840436215c896cde911489e111Paul Soulos
383245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell    private List<View> calculateEntriesToRemoveDuringCollapse() {
384245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell        final List<View> viewsToRemove = getViewsToDisplay(true);
385245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell        final List<View> viewsCollapsed = getViewsToDisplay(false);
386245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell        viewsToRemove.removeAll(viewsCollapsed);
387245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell        return viewsToRemove;
388245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell    }
389245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell
3902d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private void insertEntriesIntoViewGroup() {
3912d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        mEntriesViewGroup.removeAllViews();
39260e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos
393245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell        for (View view : getViewsToDisplay(mIsExpanded)) {
394245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell            mEntriesViewGroup.addView(view);
395245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell        }
396245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell
397245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell        removeView(mExpandCollapseButton);
398245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell        if (mCollapsedEntriesCount < mNumEntries
399245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell                && mExpandCollapseButton.getParent() == null && !mIsAlwaysExpanded) {
400245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell            mContainer.addView(mExpandCollapseButton, -1);
401245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell        }
402245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell    }
403245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell
404245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell    /**
405245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell     * Returns the list of views that should be displayed. This changes depending on whether
406245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell     * the card is expanded or collapsed.
407245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell     */
408245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell    private List<View> getViewsToDisplay(boolean isExpanded) {
409245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell        final List<View> viewsToDisplay = new ArrayList<View>();
410245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell        if (isExpanded) {
411cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos            for (int i = 0; i < mEntryViews.size(); i++) {
412cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos                List<View> viewList = mEntryViews.get(i);
413cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos                if (i > 0) {
414cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos                    View separator;
415cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos                    if (mSeparators.size() <= i - 1) {
416cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos                        separator = generateSeparator(viewList.get(0));
417cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos                        mSeparators.add(separator);
418cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos                    } else {
419cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos                        separator = mSeparators.get(i - 1);
420cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos                    }
421245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell                    viewsToDisplay.add(separator);
42297ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                }
42360e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos                for (View view : viewList) {
424245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell                    viewsToDisplay.add(view);
42560e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos                }
42660e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            }
42760e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos        } else {
428691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos            // We want to insert mCollapsedEntriesCount entries into the group. extraEntries is the
429691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos            // number of entries that need to be added that are not the head element of a list
430691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos            // to reach mCollapsedEntriesCount.
431691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos            int numInViewGroup = 0;
432691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos            int extraEntries = mCollapsedEntriesCount - mEntryViews.size();
433691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos            for (int i = 0; i < mEntryViews.size() && numInViewGroup < mCollapsedEntriesCount;
434691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos                    i++) {
435691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos                List<View> entryViewList = mEntryViews.get(i);
43697ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                if (i > 0) {
437cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos                    View separator;
438cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos                    if (mSeparators.size() <= i - 1) {
439cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos                        separator = generateSeparator(entryViewList.get(0));
440cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos                        mSeparators.add(separator);
441cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos                    } else {
442cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos                        separator = mSeparators.get(i - 1);
443cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos                    }
444245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell                    viewsToDisplay.add(separator);
445691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos                }
446245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell                viewsToDisplay.add(entryViewList.get(0));
447691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos                numInViewGroup++;
44805287bf0cea303b93802a629aa883fb6322ca342Brian Attwell
44905287bf0cea303b93802a629aa883fb6322ca342Brian Attwell                int indexInEntryViewList = 1;
45005287bf0cea303b93802a629aa883fb6322ca342Brian Attwell                if (mShowFirstEntryTypeTwice && i == 0 && entryViewList.size() > 1) {
45105287bf0cea303b93802a629aa883fb6322ca342Brian Attwell                    viewsToDisplay.add(entryViewList.get(1));
45205287bf0cea303b93802a629aa883fb6322ca342Brian Attwell                    numInViewGroup++;
45305287bf0cea303b93802a629aa883fb6322ca342Brian Attwell                    extraEntries--;
45405287bf0cea303b93802a629aa883fb6322ca342Brian Attwell                    indexInEntryViewList++;
45505287bf0cea303b93802a629aa883fb6322ca342Brian Attwell                }
45605287bf0cea303b93802a629aa883fb6322ca342Brian Attwell
457691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos                // Insert entries in this list to hit mCollapsedEntriesCount.
45805287bf0cea303b93802a629aa883fb6322ca342Brian Attwell                for (int j = indexInEntryViewList;
459691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos                        j < entryViewList.size() && numInViewGroup < mCollapsedEntriesCount &&
460691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos                        extraEntries > 0;
461691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos                        j++) {
462245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell                    viewsToDisplay.add(entryViewList.get(j));
463691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos                    numInViewGroup++;
464691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos                    extraEntries--;
46597ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                }
4662d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            }
4672d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
4682d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
469245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell        formatEntryIfFirst(viewsToDisplay);
470245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell        return viewsToDisplay;
4712d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
4722d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
473245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell    private void formatEntryIfFirst(List<View> entriesViewGroup) {
4741321736e0b6f4da580aa77075dd3845c8781f460Paul Soulos        // If no title and the first entry in the group, add extra padding
4751321736e0b6f4da580aa77075dd3845c8781f460Paul Soulos        if (TextUtils.isEmpty(mTitleTextView.getText()) &&
476245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell                entriesViewGroup.size() > 0) {
477245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell            final View entry = entriesViewGroup.get(0);
4781321736e0b6f4da580aa77075dd3845c8781f460Paul Soulos            entry.setPadding(entry.getPaddingLeft(),
479568d5d82610f87a5e733690e57075f0a99551972Paul Soulos                    getResources().getDimensionPixelSize(
480568d5d82610f87a5e733690e57075f0a99551972Paul Soulos                            R.dimen.expanding_entry_card_item_padding_top) +
481568d5d82610f87a5e733690e57075f0a99551972Paul Soulos                    getResources().getDimensionPixelSize(
4821321736e0b6f4da580aa77075dd3845c8781f460Paul Soulos                            R.dimen.expanding_entry_card_null_title_top_extra_padding),
4831321736e0b6f4da580aa77075dd3845c8781f460Paul Soulos                    entry.getPaddingRight(),
4841321736e0b6f4da580aa77075dd3845c8781f460Paul Soulos                    entry.getPaddingBottom());
4851321736e0b6f4da580aa77075dd3845c8781f460Paul Soulos        }
4862d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
4872d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
488cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos    private View generateSeparator(View entry) {
4890cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        View separator = new View(getContext());
490ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos        Resources res = getResources();
491ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos
492ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos        separator.setBackgroundColor(res.getColor(
493daa2058979fda84a0ce22e21edd53aa049e80aa0Brian Attwell                R.color.divider_line_color_light));
494ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos        LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
49505287bf0cea303b93802a629aa883fb6322ca342Brian Attwell                ViewGroup.LayoutParams.MATCH_PARENT, mDividerLineHeightPixels);
4960cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        // The separator is aligned with the text in the entry. This is offset by a default
4970cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        // margin. If there is an icon present, the icon's width and margin are added
498ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos        int marginStart = res.getDimensionPixelSize(
4990cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos                R.dimen.expanding_entry_card_item_padding_start);
5000cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        ImageView entryIcon = (ImageView) entry.findViewById(R.id.icon);
50197ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos        if (entryIcon.getVisibility() == View.VISIBLE) {
5020cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            int imageWidthAndMargin =
503ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos                    res.getDimensionPixelSize(R.dimen.expanding_entry_card_item_icon_width) +
504ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos                    res.getDimensionPixelSize(R.dimen.expanding_entry_card_item_image_spacing);
5050cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            marginStart += imageWidthAndMargin;
5060cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        }
50797ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos        layoutParams.setMarginStart(marginStart);
5080cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        separator.setLayoutParams(layoutParams);
509cc5ec22992ee61d130cb2ee99a038fb1761b8d35Paul Soulos        return separator;
5100cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos    }
5110cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
5122d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private CharSequence getExpandButtonText() {
5132d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        if (!TextUtils.isEmpty(mExpandButtonText)) {
5142d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            return mExpandButtonText;
5152d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        } else {
5162d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            // Default to "See more".
5172d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            return getResources().getText(R.string.expanding_entry_card_view_see_more);
5182d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
5192d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
5202d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
5212d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private CharSequence getCollapseButtonText() {
5222d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        if (!TextUtils.isEmpty(mCollapseButtonText)) {
5232d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            return mCollapseButtonText;
5242d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        } else {
5252d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            // Default to "See less".
5262d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            return getResources().getText(R.string.expanding_entry_card_view_see_less);
5272d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
5282d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
5292d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
5300d49d81a3df2eea40dfe57570767c7661463f2dcBrian Attwell    /**
53160e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos     * Inflates the initial entries to be shown.
5320d49d81a3df2eea40dfe57570767c7661463f2dcBrian Attwell     */
53360e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos    private void inflateInitialEntries(LayoutInflater layoutInflater) {
53460e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos        // If the number of collapsed entries equals total entries, inflate all
53560e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos        if (mCollapsedEntriesCount == mNumEntries) {
53660e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            inflateAllEntries(layoutInflater);
53760e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos        } else {
53860e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            // Otherwise inflate the top entry from each list
539691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos            // extraEntries is used to add extra entries until mCollapsedEntriesCount is reached.
540691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos            int numInflated = 0;
541691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos            int extraEntries = mCollapsedEntriesCount - mEntries.size();
542691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos            for (int i = 0; i < mEntries.size() && numInflated < mCollapsedEntriesCount; i++) {
543691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos                List<Entry> entryList = mEntries.get(i);
544691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos                List<View> entryViewList = mEntryViews.get(i);
545691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos
546691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos                entryViewList.add(createEntryView(layoutInflater, entryList.get(0),
54797ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                        /* showIcon = */ View.VISIBLE));
548691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos                numInflated++;
54905287bf0cea303b93802a629aa883fb6322ca342Brian Attwell
55005287bf0cea303b93802a629aa883fb6322ca342Brian Attwell                int indexInEntryViewList = 1;
55105287bf0cea303b93802a629aa883fb6322ca342Brian Attwell                if (mShowFirstEntryTypeTwice && i == 0 && entryList.size() > 1) {
55205287bf0cea303b93802a629aa883fb6322ca342Brian Attwell                    entryViewList.add(createEntryView(layoutInflater, entryList.get(1),
55305287bf0cea303b93802a629aa883fb6322ca342Brian Attwell                        /* showIcon = */ View.INVISIBLE));
55405287bf0cea303b93802a629aa883fb6322ca342Brian Attwell                    numInflated++;
55505287bf0cea303b93802a629aa883fb6322ca342Brian Attwell                    extraEntries--;
55605287bf0cea303b93802a629aa883fb6322ca342Brian Attwell                    indexInEntryViewList++;
55705287bf0cea303b93802a629aa883fb6322ca342Brian Attwell                }
55805287bf0cea303b93802a629aa883fb6322ca342Brian Attwell
559691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos                // Inflate entries in this list to hit mCollapsedEntriesCount.
56005287bf0cea303b93802a629aa883fb6322ca342Brian Attwell                for (int j = indexInEntryViewList; j < entryList.size()
56105287bf0cea303b93802a629aa883fb6322ca342Brian Attwell                        && numInflated < mCollapsedEntriesCount
56205287bf0cea303b93802a629aa883fb6322ca342Brian Attwell                        && extraEntries > 0; j++) {
563691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos                    entryViewList.add(createEntryView(layoutInflater, entryList.get(j),
56443e0dead719568ed610f9f111f6e7614368445efPaul Soulos                            /* showIcon = */ View.INVISIBLE));
565691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos                    numInflated++;
566691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos                    extraEntries--;
567691dd8fc7ce4b330cb6341f8e54fa6703564bd3ePaul Soulos                }
56860e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            }
56960e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos        }
57060e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos    }
57160e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos
57260e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos    /**
57360e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos     * Inflates all entries.
57460e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos     */
57560e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos    private void inflateAllEntries(LayoutInflater layoutInflater) {
57660e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos        if (mAllEntriesInflated) {
57760e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            return;
57860e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos        }
57960e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos        for (int i = 0; i < mEntries.size(); i++) {
58060e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            List<Entry> entryList = mEntries.get(i);
58160e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            List<View> viewList = mEntryViews.get(i);
58260e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            for (int j = viewList.size(); j < entryList.size(); j++) {
58397ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                final int iconVisibility;
58497ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                final Entry entry = entryList.get(j);
58597ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                // If the entry does not have an icon, mark gone. Else if it has an icon, show
58697ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                // for the first Entry in the list only
58797ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                if (entry.getIcon() == null) {
58897ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                    iconVisibility = View.GONE;
58997ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                } else if (j == 0) {
59097ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                    iconVisibility = View.VISIBLE;
59197ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                } else {
59297ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                    iconVisibility = View.INVISIBLE;
59397ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                }
59497ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos                viewList.add(createEntryView(layoutInflater, entry, iconVisibility));
59560e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos            }
5962d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
59760e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos        mAllEntriesInflated = true;
5982d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
5992d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
6007b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos    public void setColorAndFilter(int color, ColorFilter colorFilter) {
6017b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos        mThemeColor = color;
6027b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos        mThemeColorFilter = colorFilter;
6037b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos        applyColor();
6047b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos    }
6057b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos
6066095369885edcca566a812b551886e29c7ff8039Brian Attwell    public void setEntryHeaderColor(int color) {
6076095369885edcca566a812b551886e29c7ff8039Brian Attwell        if (mEntries != null) {
6086095369885edcca566a812b551886e29c7ff8039Brian Attwell            for (List<View> entryList : mEntryViews) {
6096095369885edcca566a812b551886e29c7ff8039Brian Attwell                for (View entryView : entryList) {
6106095369885edcca566a812b551886e29c7ff8039Brian Attwell                    TextView header = (TextView) entryView.findViewById(R.id.header);
6116095369885edcca566a812b551886e29c7ff8039Brian Attwell                    if (header != null) {
6126095369885edcca566a812b551886e29c7ff8039Brian Attwell                        header.setTextColor(color);
6136095369885edcca566a812b551886e29c7ff8039Brian Attwell                    }
6146095369885edcca566a812b551886e29c7ff8039Brian Attwell                }
6156095369885edcca566a812b551886e29c7ff8039Brian Attwell            }
6166095369885edcca566a812b551886e29c7ff8039Brian Attwell        }
6176095369885edcca566a812b551886e29c7ff8039Brian Attwell    }
6186095369885edcca566a812b551886e29c7ff8039Brian Attwell
6197b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos    /**
6207b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos     * The ColorFilter is passed in along with the color so that a new one only needs to be created
6217b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos     * once for the entire activity.
6227b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos     * 1. Title
6237b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos     * 2. Entry icons
6247b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos     * 3. Expand/Collapse Text
6257b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos     * 4. Expand/Collapse Button
6267b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos     */
6277b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos    public void applyColor() {
6287b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos        if (mThemeColor != 0 && mThemeColorFilter != null) {
6297b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos            // Title
6307b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos            if (mTitleTextView != null) {
6317b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos                mTitleTextView.setTextColor(mThemeColor);
6327b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos            }
6337b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos
6347b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos            // Entry icons
6357b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos            if (mEntries != null) {
63660e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos                for (List<Entry> entryList : mEntries) {
63760e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos                    for (Entry entry : entryList) {
63848ebbaafcf467c072e4477c98ef2faba1c65af7ePaul Soulos                        if (entry.shouldApplyColor()) {
63948ebbaafcf467c072e4477c98ef2faba1c65af7ePaul Soulos                            Drawable icon = entry.getIcon();
64048ebbaafcf467c072e4477c98ef2faba1c65af7ePaul Soulos                            if (icon != null) {
6410da93008e49306e99a90b114b7f8a60c78774fc3Brian Attwell                                icon.mutate();
64248ebbaafcf467c072e4477c98ef2faba1c65af7ePaul Soulos                                icon.setColorFilter(mThemeColorFilter);
64348ebbaafcf467c072e4477c98ef2faba1c65af7ePaul Soulos                            }
64460e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos                        }
645dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                        Drawable alternateIcon = entry.getAlternateIcon();
646dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                        if (alternateIcon != null) {
6470da93008e49306e99a90b114b7f8a60c78774fc3Brian Attwell                            alternateIcon.mutate();
648dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                            alternateIcon.setColorFilter(mThemeColorFilter);
649dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos                        }
65048fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                        Drawable thirdIcon = entry.getThirdIcon();
65148fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                        if (thirdIcon != null) {
6520da93008e49306e99a90b114b7f8a60c78774fc3Brian Attwell                            thirdIcon.mutate();
65348fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                            thirdIcon.setColorFilter(mThemeColorFilter);
65448fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                        }
655eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos                    }
6567b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos                }
6577b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos            }
6587b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos
6597b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos            // Expand/Collapse
6607b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos            mExpandCollapseTextView.setTextColor(mThemeColor);
661c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos            mExpandCollapseArrow.setColorFilter(mThemeColorFilter);
6627b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos        }
6637b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos    }
6647b0b0ce616c6c2fa149918c112128388712f5657Paul Soulos
6652a4207fb39330e840436215c896cde911489e111Paul Soulos    private View createEntryView(LayoutInflater layoutInflater, final Entry entry,
6662a4207fb39330e840436215c896cde911489e111Paul Soulos            int iconVisibility) {
6672a4207fb39330e840436215c896cde911489e111Paul Soulos        final EntryView view = (EntryView) layoutInflater.inflate(
6682d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos                R.layout.expanding_entry_card_item, this, false);
6692d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
6702a4207fb39330e840436215c896cde911489e111Paul Soulos        view.setContextMenuInfo(entry.getEntryContextMenuInfo());
67123e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos        if (!TextUtils.isEmpty(entry.getPrimaryContentDescription())) {
67223e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos            view.setContentDescription(entry.getPrimaryContentDescription());
67323e2836c1e9cbe8996a1344301e69d67bb617891Paul Soulos        }
674ea5e0b715030f1b0e8015defd10842127a8a4121Paul Soulos
675dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        final ImageView icon = (ImageView) view.findViewById(R.id.icon);
67697ed5019d75bd6afdfd5f3a8150161d9d9441275Paul Soulos        icon.setVisibility(iconVisibility);
677eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        if (entry.getIcon() != null) {
678eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos            icon.setImageDrawable(entry.getIcon());
679eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        }
680dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        final TextView header = (TextView) view.findViewById(R.id.header);
68103ece86bc2bda7f29aa2f8f2111035e4c6c6b871Paul Soulos        if (!TextUtils.isEmpty(entry.getHeader())) {
6822d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            header.setText(entry.getHeader());
6832d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        } else {
6842d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            header.setVisibility(View.GONE);
6852d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
6862d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
687dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        final TextView subHeader = (TextView) view.findViewById(R.id.sub_header);
68803ece86bc2bda7f29aa2f8f2111035e4c6c6b871Paul Soulos        if (!TextUtils.isEmpty(entry.getSubHeader())) {
6892d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            subHeader.setText(entry.getSubHeader());
6902d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        } else {
6912d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            subHeader.setVisibility(View.GONE);
6922d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
6932d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
694dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        final ImageView subHeaderIcon = (ImageView) view.findViewById(R.id.icon_sub_header);
6952d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        if (entry.getSubHeaderIcon() != null) {
6962d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            subHeaderIcon.setImageDrawable(entry.getSubHeaderIcon());
6972d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        } else {
6982d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            subHeaderIcon.setVisibility(View.GONE);
6992d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
7002d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
701dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        final TextView text = (TextView) view.findViewById(R.id.text);
70203ece86bc2bda7f29aa2f8f2111035e4c6c6b871Paul Soulos        if (!TextUtils.isEmpty(entry.getText())) {
7032d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            text.setText(entry.getText());
7042d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        } else {
7052d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            text.setVisibility(View.GONE);
7062d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
7072d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
708dd7419d90cda5c52e81491bea3cf3c3f4e0535c7Paul Soulos        final ImageView textIcon = (ImageView) view.findViewById(R.id.icon_text);
7092d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        if (entry.getTextIcon() != null) {
7102d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            textIcon.setImageDrawable(entry.getTextIcon());
7112d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        } else {
7122d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            textIcon.setVisibility(View.GONE);
7132d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
7142d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
7152d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        if (entry.getIntent() != null) {
7167d22b94ce50f7a65dd89d4533f2aa3a3392e7972Paul Soulos            view.setOnClickListener(mOnClickListener);
7172ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos            view.setTag(new EntryTag(entry.getId(), entry.getIntent()));
7182d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
7192d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
720a42ef76251778161d27bc07db214b8c81720e476Paul Soulos        if (entry.getIntent() == null && entry.getEntryContextMenuInfo() == null) {
721a42ef76251778161d27bc07db214b8c81720e476Paul Soulos            // Remove the click effect
722a42ef76251778161d27bc07db214b8c81720e476Paul Soulos            view.setBackground(null);
723a42ef76251778161d27bc07db214b8c81720e476Paul Soulos        }
724a42ef76251778161d27bc07db214b8c81720e476Paul Soulos
725ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos        // If only the header is visible, add a top margin to match icon's top margin.
726ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos        // Also increase the space below the header for visual comfort.
7274b943553afdb7286b33e4bc2481431e816c57967Paul Soulos        if (header.getVisibility() == View.VISIBLE && subHeader.getVisibility() == View.GONE &&
7284b943553afdb7286b33e4bc2481431e816c57967Paul Soulos                text.getVisibility() == View.GONE) {
7294b943553afdb7286b33e4bc2481431e816c57967Paul Soulos            RelativeLayout.LayoutParams headerLayoutParams =
7304b943553afdb7286b33e4bc2481431e816c57967Paul Soulos                    (RelativeLayout.LayoutParams) header.getLayoutParams();
7314b943553afdb7286b33e4bc2481431e816c57967Paul Soulos            headerLayoutParams.topMargin = (int) (getResources().getDimension(
732ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos                    R.dimen.expanding_entry_card_item_header_only_margin_top));
733ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos            headerLayoutParams.bottomMargin += (int) (getResources().getDimension(
734ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos                    R.dimen.expanding_entry_card_item_header_only_margin_bottom));
7354b943553afdb7286b33e4bc2481431e816c57967Paul Soulos            header.setLayoutParams(headerLayoutParams);
7364b943553afdb7286b33e4bc2481431e816c57967Paul Soulos        }
7374b943553afdb7286b33e4bc2481431e816c57967Paul Soulos
738edd44f03e0e7aa57d4eb721147d4a3f3d2551c1aPaul Soulos        // Adjust the top padding size for entries with an invisible icon. The padding depends on
739edd44f03e0e7aa57d4eb721147d4a3f3d2551c1aPaul Soulos        // if there is a sub header or text section
740edd44f03e0e7aa57d4eb721147d4a3f3d2551c1aPaul Soulos        if (iconVisibility == View.INVISIBLE &&
741edd44f03e0e7aa57d4eb721147d4a3f3d2551c1aPaul Soulos                (!TextUtils.isEmpty(entry.getSubHeader()) || !TextUtils.isEmpty(entry.getText()))) {
742edd44f03e0e7aa57d4eb721147d4a3f3d2551c1aPaul Soulos            view.setPaddingRelative(view.getPaddingStart(),
743edd44f03e0e7aa57d4eb721147d4a3f3d2551c1aPaul Soulos                    getResources().getDimensionPixelSize(
744edd44f03e0e7aa57d4eb721147d4a3f3d2551c1aPaul Soulos                            R.dimen.expanding_entry_card_item_no_icon_margin_top),
745edd44f03e0e7aa57d4eb721147d4a3f3d2551c1aPaul Soulos                    view.getPaddingEnd(),
746edd44f03e0e7aa57d4eb721147d4a3f3d2551c1aPaul Soulos                    view.getPaddingBottom());
747edd44f03e0e7aa57d4eb721147d4a3f3d2551c1aPaul Soulos        } else if (iconVisibility == View.INVISIBLE &&  TextUtils.isEmpty(entry.getSubHeader())
748edd44f03e0e7aa57d4eb721147d4a3f3d2551c1aPaul Soulos                && TextUtils.isEmpty(entry.getText())) {
749ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos            view.setPaddingRelative(view.getPaddingStart(), 0, view.getPaddingEnd(),
750ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos                    view.getPaddingBottom());
751ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos        }
752ac9b31665c157e6aa7bce487a5467e8abd8224d5Paul Soulos
75348fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        final ImageView alternateIcon = (ImageView) view.findViewById(R.id.icon_alternate);
75448fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        final ImageView thirdIcon = (ImageView) view.findViewById(R.id.third_icon);
75548fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos
75648fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        if (entry.getAlternateIcon() != null && entry.getAlternateIntent() != null) {
75748fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            alternateIcon.setImageDrawable(entry.getAlternateIcon());
75848fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            alternateIcon.setOnClickListener(mOnClickListener);
75948fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            alternateIcon.setTag(new EntryTag(entry.getId(), entry.getAlternateIntent()));
76048fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            alternateIcon.setVisibility(View.VISIBLE);
76148fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            alternateIcon.setContentDescription(entry.getAlternateContentDescription());
76248fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        }
76348fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos
76448fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        if (entry.getThirdIcon() != null && entry.getThirdIntent() != null) {
76548fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            thirdIcon.setImageDrawable(entry.getThirdIcon());
76648fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            thirdIcon.setOnClickListener(mOnClickListener);
76748fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            thirdIcon.setTag(new EntryTag(entry.getId(), entry.getThirdIntent()));
76848fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            thirdIcon.setVisibility(View.VISIBLE);
76948fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            thirdIcon.setContentDescription(entry.getThirdContentDescription());
77048fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        }
77148fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos
77248fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        // Set a custom touch listener for expanding the extra icon touch areas
77348fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        view.setOnTouchListener(new EntryTouchListener(view, alternateIcon, thirdIcon));
7742a4207fb39330e840436215c896cde911489e111Paul Soulos        view.setOnCreateContextMenuListener(mOnCreateContextMenuListener);
7752a4207fb39330e840436215c896cde911489e111Paul Soulos
7762d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        return view;
7772d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
7782d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
779c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos    private void updateExpandCollapseButton(CharSequence buttonText, long duration) {
780c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos        if (mIsExpanded) {
781c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos            final ObjectAnimator animator = ObjectAnimator.ofFloat(mExpandCollapseArrow,
782c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos                    "rotation", 180);
783c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos            animator.setDuration(duration);
784c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos            animator.start();
7852d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        } else {
786c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos            final ObjectAnimator animator = ObjectAnimator.ofFloat(mExpandCollapseArrow,
787c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos                    "rotation", 0);
788c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos            animator.setDuration(duration);
789c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos            animator.start();
7902d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
791c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos        updateBadges();
792c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos
7932d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        mExpandCollapseTextView.setText(buttonText);
7942d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
7952d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
7966b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos    private void updateBadges() {
7976b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos        if (mIsExpanded) {
7986b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos            mBadgeContainer.removeAllViews();
7996b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos        } else {
80005287bf0cea303b93802a629aa883fb6322ca342Brian Attwell            int numberOfMimeTypesShown = mCollapsedEntriesCount;
80105287bf0cea303b93802a629aa883fb6322ca342Brian Attwell            if (mShowFirstEntryTypeTwice && mEntries.size() > 0
80205287bf0cea303b93802a629aa883fb6322ca342Brian Attwell                    && mEntries.get(0).size() > 1) {
80305287bf0cea303b93802a629aa883fb6322ca342Brian Attwell                numberOfMimeTypesShown--;
80405287bf0cea303b93802a629aa883fb6322ca342Brian Attwell            }
8056b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos            // Inflate badges if not yet created
80605287bf0cea303b93802a629aa883fb6322ca342Brian Attwell            if (mBadges.size() < mEntries.size() - numberOfMimeTypesShown) {
80705287bf0cea303b93802a629aa883fb6322ca342Brian Attwell                for (int i = numberOfMimeTypesShown; i < mEntries.size(); i++) {
8086b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos                    Drawable badgeDrawable = mEntries.get(i).get(0).getIcon();
80948290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                    int badgeResourceId = mEntries.get(i).get(0).getIconResourceId();
81048290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                    // Do not add the same badge twice
81148290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                    if (badgeResourceId != 0 && mBadgeIds.contains(badgeResourceId)) {
81248290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                        continue;
81348290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                    }
8146b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos                    if (badgeDrawable != null) {
8156b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos                        ImageView badgeView = new ImageView(getContext());
8166b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos                        LinearLayout.LayoutParams badgeViewParams = new LinearLayout.LayoutParams(
8176b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos                                (int) getResources().getDimension(
8186b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos                                        R.dimen.expanding_entry_card_item_icon_width),
8196b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos                                (int) getResources().getDimension(
8206b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos                                        R.dimen.expanding_entry_card_item_icon_height));
8216b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos                        badgeViewParams.setMarginEnd((int) getResources().getDimension(
8226b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos                                R.dimen.expanding_entry_card_badge_separator_margin));
8236b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos                        badgeView.setLayoutParams(badgeViewParams);
8246b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos                        badgeView.setImageDrawable(badgeDrawable);
8256b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos                        mBadges.add(badgeView);
82648290bed7c6a8bd5e7be8b206dddacf9047a945fPaul Soulos                        mBadgeIds.add(badgeResourceId);
8276b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos                    }
8286b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos                }
8296b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos            }
8306b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos            mBadgeContainer.removeAllViews();
8316b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos            for (ImageView badge : mBadges) {
8326b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos                mBadgeContainer.addView(badge);
8336b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos            }
8346b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos        }
8356b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos    }
8366b6328915d66f0c5947badc3d1973c31f29eef62Paul Soulos
8372d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private void expand() {
8380cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        ChangeBounds boundsTransition = new ChangeBounds();
8390cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        boundsTransition.setDuration(DURATION_EXPAND_ANIMATION_CHANGE_BOUNDS);
8400cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
8410cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        Fade fadeIn = new Fade(Fade.IN);
8420cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        fadeIn.setDuration(DURATION_EXPAND_ANIMATION_FADE_IN);
8430cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        fadeIn.setStartDelay(DELAY_EXPAND_ANIMATION_FADE_IN);
8440cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
8450cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        TransitionSet transitionSet = new TransitionSet();
8460cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        transitionSet.addTransition(boundsTransition);
8470cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        transitionSet.addTransition(fadeIn);
8480cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
8494cd9ed68dca5f4adeb8ec2065526c18f33af5926Paul Soulos        transitionSet.excludeTarget(R.id.text, /* exclude = */ true);
8504cd9ed68dca5f4adeb8ec2065526c18f33af5926Paul Soulos
8510cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        final ViewGroup transitionViewContainer = mAnimationViewGroup == null ?
8520cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos                this : mAnimationViewGroup;
8530cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
8540cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        transitionSet.addListener(new TransitionListener() {
8550cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            @Override
8560cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            public void onTransitionStart(Transition transition) {
857245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell                mListener.onExpand();
8580cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            }
8590cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
8600cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            @Override
8610cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            public void onTransitionEnd(Transition transition) {
862245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell                mListener.onExpandDone();
8630cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            }
8640cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
8650cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            @Override
8660cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            public void onTransitionCancel(Transition transition) {
8670cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            }
8680cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
8690cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            @Override
8700cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            public void onTransitionPause(Transition transition) {
8710cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            }
8720cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
8730cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            @Override
8740cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            public void onTransitionResume(Transition transition) {
8750cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            }
8760cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        });
8770cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
8780cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos        TransitionManager.beginDelayedTransition(transitionViewContainer, transitionSet);
8792d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
8802d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        mIsExpanded = true;
8810d49d81a3df2eea40dfe57570767c7661463f2dcBrian Attwell        // In order to insert new entries, we may need to inflate them for the first time
88260e5108e39e54d0a7e4c6924b33597d338be3fb9Paul Soulos        inflateAllEntries(LayoutInflater.from(getContext()));
8832d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        insertEntriesIntoViewGroup();
884c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos        updateExpandCollapseButton(getCollapseButtonText(),
885c205cf1d4db6a85f52175af0add8852d5e1f8605Paul Soulos                DURATION_EXPAND_ANIMATION_CHANGE_BOUNDS);
8862d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
8872d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
8882d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    private void collapse() {
889245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell        final List<View> views = calculateEntriesToRemoveDuringCollapse();
890245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell
891245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell        // This animation requires layout changes, unlike the expand() animation: the action bar
892245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell        // might get scrolled open in order to fill empty space. As a result, we can't use
893245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell        // ChangeBounds here. Instead manually animate view height and alpha. This isn't as
894245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell        // efficient as the bounds and translation changes performed by ChangeBounds. Nonetheless, a
895245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell        // reasonable frame-rate is achieved collapsing a dozen elements on a user Svelte N4. So the
896245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell        // performance hit doesn't justify writing a less maintainable animation.
897245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell        final AnimatorSet set = new AnimatorSet();
898245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell        final List<Animator> animators = new ArrayList<Animator>(views.size());
899245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell        int totalSizeChange = 0;
900245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell        for (View viewToRemove : views) {
901245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell            final ObjectAnimator animator = ObjectAnimator.ofObject(viewToRemove,
902245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell                    VIEW_LAYOUT_HEIGHT_PROPERTY, null, viewToRemove.getHeight(), 0);
903245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell            totalSizeChange += viewToRemove.getHeight();
904245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell            animator.setDuration(DURATION_COLLAPSE_ANIMATION_CHANGE_BOUNDS);
905245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell            animators.add(animator);
906245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell            viewToRemove.animate().alpha(0).setDuration(DURATION_COLLAPSE_ANIMATION_FADE_OUT);
907245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell        }
908245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell        set.playTogether(animators);
909245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell        set.start();
910245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell        set.addListener(new AnimatorListener() {
9110cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            @Override
912245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell            public void onAnimationStart(Animator animation) {
9130cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            }
9140cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
9152d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            @Override
916245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell            public void onAnimationEnd(Animator animation) {
917245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell                // Now that the views have been animated away, actually remove them from the view
918245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell                // hierarchy. Reset their appearance so that they look appropriate when they
91905287bf0cea303b93802a629aa883fb6322ca342Brian Attwell                // get added back later.
920245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell                insertEntriesIntoViewGroup();
921245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell                for (View view : views) {
92205287bf0cea303b93802a629aa883fb6322ca342Brian Attwell                    if (view instanceof EntryView) {
92305287bf0cea303b93802a629aa883fb6322ca342Brian Attwell                        VIEW_LAYOUT_HEIGHT_PROPERTY.set(view, LayoutParams.WRAP_CONTENT);
92405287bf0cea303b93802a629aa883fb6322ca342Brian Attwell                    } else {
92505287bf0cea303b93802a629aa883fb6322ca342Brian Attwell                        VIEW_LAYOUT_HEIGHT_PROPERTY.set(view, mDividerLineHeightPixels);
92605287bf0cea303b93802a629aa883fb6322ca342Brian Attwell                    }
927245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell                    view.animate().cancel();
928245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell                    view.setAlpha(1);
929245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell                }
9300cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            }
9310cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
9320cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            @Override
933245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell            public void onAnimationCancel(Animator animation) {
9340cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            }
9350cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
9360cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos            @Override
937245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell            public void onAnimationRepeat(Animator animation) {
9382d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            }
9392d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        });
9400cda9aeb01f1922fce2a9e87ae4c0146c177b4f0Paul Soulos
941245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell        mListener.onCollapse(totalSizeChange);
942245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell        mIsExpanded = false;
943245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell        updateExpandCollapseButton(getExpandButtonText(),
944245d3d2000150cbb21111370f42addaeeb1b10a0Brian Attwell                DURATION_COLLAPSE_ANIMATION_CHANGE_BOUNDS);
9452d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
9462d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
9472d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    /**
9482d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     * Returns whether the view is currently in its expanded state.
9492d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     */
9502d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    public boolean isExpanded() {
9512d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        return mIsExpanded;
9522d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
9532d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos
9542d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    /**
9552d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     * Sets the title text of this ExpandingEntryCardView.
9562fa690807a94708384789b211965bfc75b5ac38ePaul Soulos     * @param title The title to set. A null title will result in the title being removed.
9572d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos     */
9582d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    public void setTitle(String title) {
9592d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        if (mTitleTextView == null) {
9602d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos            Log.e(TAG, "mTitleTextView is null");
9612d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        }
9622d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos        mTitleTextView.setText(title);
9631321736e0b6f4da580aa77075dd3845c8781f460Paul Soulos        mTitleTextView.setVisibility(TextUtils.isEmpty(title) ? View.GONE : View.VISIBLE);
9641321736e0b6f4da580aa77075dd3845c8781f460Paul Soulos        findViewById(R.id.title_separator).setVisibility(TextUtils.isEmpty(title) ?
9651321736e0b6f4da580aa77075dd3845c8781f460Paul Soulos                View.GONE : View.VISIBLE);
9661321736e0b6f4da580aa77075dd3845c8781f460Paul Soulos        // If the title is set after children have been added, reset the top entry's padding to
9671321736e0b6f4da580aa77075dd3845c8781f460Paul Soulos        // the default. Else if the title is cleared after children have been added, set
9681321736e0b6f4da580aa77075dd3845c8781f460Paul Soulos        // the extra top padding
9691321736e0b6f4da580aa77075dd3845c8781f460Paul Soulos        if (!TextUtils.isEmpty(title) && mEntriesViewGroup.getChildCount() > 0) {
9701321736e0b6f4da580aa77075dd3845c8781f460Paul Soulos            View firstEntry = mEntriesViewGroup.getChildAt(0);
9711321736e0b6f4da580aa77075dd3845c8781f460Paul Soulos            firstEntry.setPadding(firstEntry.getPaddingLeft(),
9721321736e0b6f4da580aa77075dd3845c8781f460Paul Soulos                    getResources().getDimensionPixelSize(
9731321736e0b6f4da580aa77075dd3845c8781f460Paul Soulos                            R.dimen.expanding_entry_card_item_padding_top),
9741321736e0b6f4da580aa77075dd3845c8781f460Paul Soulos                    firstEntry.getPaddingRight(),
9751321736e0b6f4da580aa77075dd3845c8781f460Paul Soulos                    firstEntry.getPaddingBottom());
9761321736e0b6f4da580aa77075dd3845c8781f460Paul Soulos        } else if (!TextUtils.isEmpty(title) && mEntriesViewGroup.getChildCount() > 0) {
9771321736e0b6f4da580aa77075dd3845c8781f460Paul Soulos            View firstEntry = mEntriesViewGroup.getChildAt(0);
9781321736e0b6f4da580aa77075dd3845c8781f460Paul Soulos            firstEntry.setPadding(firstEntry.getPaddingLeft(),
9791321736e0b6f4da580aa77075dd3845c8781f460Paul Soulos                    getResources().getDimensionPixelSize(
9801321736e0b6f4da580aa77075dd3845c8781f460Paul Soulos                            R.dimen.expanding_entry_card_item_padding_top) +
9811321736e0b6f4da580aa77075dd3845c8781f460Paul Soulos                            getResources().getDimensionPixelSize(
9821321736e0b6f4da580aa77075dd3845c8781f460Paul Soulos                                    R.dimen.expanding_entry_card_null_title_top_extra_padding),
9831321736e0b6f4da580aa77075dd3845c8781f460Paul Soulos                    firstEntry.getPaddingRight(),
9848897287c19b394c1f0b402e6291ff4304acacbc2Brian Attwell                    firstEntry.getPaddingBottom());
9851321736e0b6f4da580aa77075dd3845c8781f460Paul Soulos        }
9862d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos    }
987eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos
988eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    public boolean shouldShow() {
989eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos        return mEntries != null && mEntries.size() > 0;
990eb64a4b5c51b39fe56ba4ef97dfff73fdcdf8c75Paul Soulos    }
9912a4207fb39330e840436215c896cde911489e111Paul Soulos
9922a4207fb39330e840436215c896cde911489e111Paul Soulos    public static final class EntryView extends RelativeLayout {
9932a4207fb39330e840436215c896cde911489e111Paul Soulos        private EntryContextMenuInfo mEntryContextMenuInfo;
9942a4207fb39330e840436215c896cde911489e111Paul Soulos
9952a4207fb39330e840436215c896cde911489e111Paul Soulos        public EntryView(Context context) {
9962a4207fb39330e840436215c896cde911489e111Paul Soulos            super(context);
9972a4207fb39330e840436215c896cde911489e111Paul Soulos        }
9982a4207fb39330e840436215c896cde911489e111Paul Soulos
9992a4207fb39330e840436215c896cde911489e111Paul Soulos        public EntryView(Context context, AttributeSet attrs) {
10002a4207fb39330e840436215c896cde911489e111Paul Soulos            super(context, attrs);
10012a4207fb39330e840436215c896cde911489e111Paul Soulos        }
10022a4207fb39330e840436215c896cde911489e111Paul Soulos
10032a4207fb39330e840436215c896cde911489e111Paul Soulos        public void setContextMenuInfo(EntryContextMenuInfo info) {
10042a4207fb39330e840436215c896cde911489e111Paul Soulos            mEntryContextMenuInfo = info;
10052a4207fb39330e840436215c896cde911489e111Paul Soulos        }
10062a4207fb39330e840436215c896cde911489e111Paul Soulos
10072a4207fb39330e840436215c896cde911489e111Paul Soulos        @Override
10082a4207fb39330e840436215c896cde911489e111Paul Soulos        protected ContextMenuInfo getContextMenuInfo() {
10092a4207fb39330e840436215c896cde911489e111Paul Soulos            return mEntryContextMenuInfo;
10102a4207fb39330e840436215c896cde911489e111Paul Soulos        }
10112a4207fb39330e840436215c896cde911489e111Paul Soulos    }
10122a4207fb39330e840436215c896cde911489e111Paul Soulos
10132a4207fb39330e840436215c896cde911489e111Paul Soulos    public static final class EntryContextMenuInfo implements ContextMenuInfo {
10142a4207fb39330e840436215c896cde911489e111Paul Soulos        private final String mCopyText;
10152a4207fb39330e840436215c896cde911489e111Paul Soulos        private final String mCopyLabel;
101697f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        private final String mMimeType;
101797f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        private final long mId;
101897f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        private final boolean mIsSuperPrimary;
10192a4207fb39330e840436215c896cde911489e111Paul Soulos
102097f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        public EntryContextMenuInfo(String copyText, String copyLabel, String mimeType, long id,
102197f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos                boolean isSuperPrimary) {
10222a4207fb39330e840436215c896cde911489e111Paul Soulos            mCopyText = copyText;
10232a4207fb39330e840436215c896cde911489e111Paul Soulos            mCopyLabel = copyLabel;
102497f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            mMimeType = mimeType;
102597f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            mId = id;
102697f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            mIsSuperPrimary = isSuperPrimary;
10272a4207fb39330e840436215c896cde911489e111Paul Soulos        }
10282a4207fb39330e840436215c896cde911489e111Paul Soulos
10292a4207fb39330e840436215c896cde911489e111Paul Soulos        public String getCopyText() {
10302a4207fb39330e840436215c896cde911489e111Paul Soulos            return mCopyText;
10312a4207fb39330e840436215c896cde911489e111Paul Soulos        }
10322a4207fb39330e840436215c896cde911489e111Paul Soulos
10332a4207fb39330e840436215c896cde911489e111Paul Soulos        public String getCopyLabel() {
10342a4207fb39330e840436215c896cde911489e111Paul Soulos            return mCopyLabel;
10352a4207fb39330e840436215c896cde911489e111Paul Soulos        }
103697f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos
103797f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        public String getMimeType() {
103897f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            return mMimeType;
103997f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        }
104097f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos
104197f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        public long getId() {
104297f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            return mId;
104397f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        }
104497f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos
104597f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        public boolean isSuperPrimary() {
104697f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos            return mIsSuperPrimary;
104797f27809c3e6153ce0bc5050bc5ee466a646e8ecPaul Soulos        }
10482a4207fb39330e840436215c896cde911489e111Paul Soulos    }
10492ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos
10502ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos    static final class EntryTag {
10512ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos        private final int mId;
10522ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos        private final Intent mIntent;
10532ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos
10542ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos        public EntryTag(int id, Intent intent) {
10552ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos            mId = id;
10562ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos            mIntent = intent;
10572ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos        }
10582ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos
10592ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos        public int getId() {
10602ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos            return mId;
10612ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos        }
10622ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos
10632ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos        public Intent getIntent() {
10642ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos            return mIntent;
10652ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos        }
10662ed2a73d15bd80bced18e5924d3f84c8a9e5e5a5Paul Soulos    }
106748fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos
106848fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos    /**
106948fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos     * This custom touch listener increases the touch area for the second and third icons, if
107048fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos     * they are present. This is necessary to maintain other properties on an entry view, like
107148fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos     * using a top padding on entry. Based off of {@link android.view.TouchDelegate}
107248fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos     */
107348fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos    private static final class EntryTouchListener implements View.OnTouchListener {
107448fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        private final View mEntry;
107548fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        private final ImageView mAlternateIcon;
107648fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        private final ImageView mThirdIcon;
107748fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        /** mTouchedView locks in a view on touch down */
107848fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        private View mTouchedView;
107948fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        /** mSlop adds some space to account for touches that are just outside the hit area */
108048fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        private int mSlop;
108148fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos
108248fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        public EntryTouchListener(View entry, ImageView alternateIcon, ImageView thirdIcon) {
108348fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            mEntry = entry;
108448fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            mAlternateIcon = alternateIcon;
108548fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            mThirdIcon = thirdIcon;
108648fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            mSlop = ViewConfiguration.get(entry.getContext()).getScaledTouchSlop();
108748fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        }
108848fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos
108948fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        @Override
109048fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        public boolean onTouch(View v, MotionEvent event) {
109148fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            View touchedView = mTouchedView;
109248fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            boolean sendToTouched = false;
109348fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            boolean hit = true;
109448fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            boolean handled = false;
109548fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos
109648fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            switch (event.getAction()) {
109748fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                case MotionEvent.ACTION_DOWN:
109848fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    if (hitThirdIcon(event)) {
109948fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                        mTouchedView = mThirdIcon;
110048fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                        sendToTouched = true;
110148fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    } else if (hitAlternateIcon(event)) {
110248fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                        mTouchedView = mAlternateIcon;
110348fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                        sendToTouched = true;
110448fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    } else {
110548fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                        mTouchedView = mEntry;
110648fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                        sendToTouched = false;
110748fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    }
110848fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    touchedView = mTouchedView;
110948fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    break;
111048fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                case MotionEvent.ACTION_UP:
111148fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                case MotionEvent.ACTION_MOVE:
111248fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    sendToTouched = mTouchedView != null && mTouchedView != mEntry;
111348fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    if (sendToTouched) {
111448fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                        final Rect slopBounds = new Rect();
111548fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                        touchedView.getHitRect(slopBounds);
111648fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                        slopBounds.inset(-mSlop, -mSlop);
111748fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                        if (!slopBounds.contains((int) event.getX(), (int) event.getY())) {
111848fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                            hit = false;
111948fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                        }
112048fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    }
112148fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    break;
112248fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                case MotionEvent.ACTION_CANCEL:
112348fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    sendToTouched = mTouchedView != null && mTouchedView != mEntry;
112448fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    mTouchedView = null;
112548fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    break;
112648fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            }
112748fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            if (sendToTouched) {
112848fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                if (hit) {
112948fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    event.setLocation(touchedView.getWidth() / 2, touchedView.getHeight() / 2);
113048fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                } else {
113148fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    // Offset event coordinates to be outside the target view (in case it does
113248fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    // something like tracking pressed state)
113348fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    event.setLocation(-(mSlop * 2), -(mSlop * 2));
113448fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                }
113548fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                handled = touchedView.dispatchTouchEvent(event);
113648fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            }
113748fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            return handled;
113848fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        }
113948fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos
114048fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        private boolean hitThirdIcon(MotionEvent event) {
1141f140227beb6d9e78955a7676dc0dd3f793f72017Brian Attwell            if (mEntry.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
114248fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                return mThirdIcon.getVisibility() == View.VISIBLE &&
114348fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                        event.getX() < mThirdIcon.getRight();
114448fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            } else {
114548fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                return mThirdIcon.getVisibility() == View.VISIBLE &&
114648fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                        event.getX() > mThirdIcon.getLeft();
114748fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            }
114848fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        }
114948fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos
115048fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        /**
115148fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos         * Should be used after checking if third icon was hit
115248fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos         */
115348fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        private boolean hitAlternateIcon(MotionEvent event) {
115448fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            // LayoutParams used to add the start margin to the touch area
115548fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            final RelativeLayout.LayoutParams alternateIconParams =
115648fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                    (RelativeLayout.LayoutParams) mAlternateIcon.getLayoutParams();
1157f140227beb6d9e78955a7676dc0dd3f793f72017Brian Attwell            if (mEntry.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) {
115848fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                return mAlternateIcon.getVisibility() == View.VISIBLE &&
115948fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                        event.getX() < mAlternateIcon.getRight() + alternateIconParams.rightMargin;
116048fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            } else {
116148fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                return mAlternateIcon.getVisibility() == View.VISIBLE &&
116248fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos                        event.getX() > mAlternateIcon.getLeft() - alternateIconParams.leftMargin;
116348fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos            }
116448fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos        }
116548fc91217042fd854f0e96c2028c188e50a5e21dPaul Soulos    }
11662d48b5ae6664a7ae0ed9941f55fae9dc327bd640Paul Soulos}
1167