PhoneFavoritesTileAdapter.java revision 55d3bb4a7f70d4a4359c31b3240f5740b788e643
1dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee/*
2dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * Copyright (C) 2013 The Android Open Source Project
3dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee *
4dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * Licensed under the Apache License, Version 2.0 (the "License");
5dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * you may not use this file except in compliance with the License.
6dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * You may obtain a copy of the License at
7dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee *
8dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee *      http://www.apache.org/licenses/LICENSE-2.0
9dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee *
10dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * Unless required by applicable law or agreed to in writing, software
11dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * distributed under the License is distributed on an "AS IS" BASIS,
12dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * See the License for the specific language governing permissions and
14dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * limitations under the License.
15dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee */
16dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leepackage com.android.dialer.list;
17dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
18316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chenimport android.animation.ObjectAnimator;
19dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.content.ContentUris;
20dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.content.Context;
21dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.content.res.Resources;
22dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.database.Cursor;
23316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chenimport android.graphics.Color;
24316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chenimport android.graphics.Rect;
25dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.net.Uri;
26dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.provider.ContactsContract.CommonDataKinds.Phone;
27dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.provider.ContactsContract.Contacts;
28dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.util.Log;
29dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.view.View;
30dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.view.ViewGroup;
31dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.widget.BaseAdapter;
32dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.widget.FrameLayout;
33dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
34dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport com.android.contacts.common.ContactPhotoManager;
35dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport com.android.contacts.common.ContactTileLoaderFactory;
36dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport com.android.contacts.common.R;
37dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport com.android.contacts.common.list.ContactEntry;
38dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport com.android.contacts.common.list.ContactTileView;
39dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
40dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport java.util.ArrayList;
41dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
42dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee/**
43dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * Also allows for a configurable number of columns as well as a maximum row of tiled contacts.
44dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee *
45dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * This adapter has been rewritten to only support a maximum of one row for favorites.
46dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee *
47dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee */
48dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leepublic class PhoneFavoritesTileAdapter extends BaseAdapter {
49316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    private static final String TAG = PhoneFavoritesTileAdapter.class.getSimpleName();
50316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    private static final boolean DEBUG = false;
51dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
526a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee    public static final int ROW_LIMIT_DEFAULT = 1;
53dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
54316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    /** Time period for an animation. */
55316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    private static final int ANIMATION_LENGTH = 300;
56316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen
57316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    private final ObjectAnimator mTranslateHorizontalAnimation;
58316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    private final ObjectAnimator mTranslateVerticalAnimation;
59316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    private final ObjectAnimator mAlphaAnimation;
60316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen
61dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    private ContactTileView.Listener mListener;
62dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    private Context mContext;
63dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    private Resources mResources;
64316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen
65316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    /** Contact data stored in cache. This is used to populate the associated view. */
66316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    protected ArrayList<ContactEntry> mContactEntries = null;
67316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    /** Back up of the temporarily removed Contact during dragging. */
68316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    private ContactEntry mDraggedEntry = null;
69316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    /** Position of the temporarily removed contact in the cache. */
70316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    private int mDraggedEntryIndex = -1;
71316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    /** New position of the temporarily removed contact in the cache. */
72316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    private int mDropEntryIndex = -1;
73316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    /** Position of the contact pending removal. */
74316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    private int mPotentialRemoveEntryIndex = -1;
75316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen
76dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    private ContactPhotoManager mPhotoManager;
77dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    protected int mNumFrequents;
786a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee    protected int mNumStarred;
79dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
80dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    protected int mColumnCount;
816a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee    private int mMaxTiledRows = ROW_LIMIT_DEFAULT;
82dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    private int mStarredIndex;
83dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
84dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    protected int mIdIndex;
85dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    protected int mLookupIndex;
86dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    protected int mPhotoUriIndex;
87dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    protected int mNameIndex;
88dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    protected int mPresenceIndex;
89dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    protected int mStatusIndex;
90dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
91dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    /**
92dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * Only valid when {@link DisplayType#STREQUENT_PHONE_ONLY} is true
93dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     */
94dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    private int mPhoneNumberIndex;
95dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    private int mPhoneNumberTypeIndex;
96dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    private int mPhoneNumberLabelIndex;
97dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
98dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    private boolean mIsQuickContactEnabled = false;
99dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    private final int mPaddingInPixels;
100dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
101316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    /** Indicates whether a drag is in process. */
102316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    private boolean mInDragging = false;
103316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen
10455d3bb4a7f70d4a4359c31b3240f5740b788e643Yorke Lee    public PhoneFavoritesTileAdapter(Context context, ContactTileView.Listener listener,
105316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            int numCols) {
1066a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee        this(context, listener, numCols, ROW_LIMIT_DEFAULT);
107dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
108dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
109316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    public PhoneFavoritesTileAdapter(Context context, ContactTileView.Listener listener,
110316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            int numCols, int maxTiledRows) {
111dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mListener = listener;
112dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mContext = context;
113dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mResources = context.getResources();
114dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mColumnCount = numCols;
115dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mNumFrequents = 0;
116dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mMaxTiledRows = maxTiledRows;
117316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        mContactEntries = new ArrayList<ContactEntry>();
118dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        // Converting padding in dips to padding in pixels
119dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mPaddingInPixels = mContext.getResources()
120d6a16d364de95c8eb0d9c4f5a07d5ad6387c8470Yorke Lee                .getDimensionPixelSize(R.dimen.contact_tile_divider_padding);
121316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen
122316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        // Initiates all animations.
123316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        mAlphaAnimation = ObjectAnimator.ofFloat(null, "alpha", 1.f).setDuration(ANIMATION_LENGTH);
124316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen
125316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        mTranslateHorizontalAnimation = ObjectAnimator.ofFloat(null, "translationX", 0.f).
126316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                setDuration(ANIMATION_LENGTH);
127316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen
128316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        mTranslateVerticalAnimation = ObjectAnimator.ofFloat(null, "translationY", 0.f).setDuration(
129316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                ANIMATION_LENGTH);
130316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen
131dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        bindColumnIndices();
132dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
133dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
134dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public void setPhotoLoader(ContactPhotoManager photoLoader) {
135dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mPhotoManager = photoLoader;
136dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
137dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
138dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public void setMaxRowCount(int maxRows) {
139dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mMaxTiledRows = maxRows;
140dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
141dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
142dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public void setColumnCount(int columnCount) {
143dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mColumnCount = columnCount;
144dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
145dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
146dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public void enableQuickContact(boolean enableQuickContact) {
147dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mIsQuickContactEnabled = enableQuickContact;
148dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
149dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
150dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    /**
151316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     * Indicates whether a drag is in process.
152316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     *
153316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     * @param inDragging Boolean variable indicating whether there is a drag in process.
154316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     */
155316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    public void setInDragging(boolean inDragging) {
156316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        mInDragging = inDragging;
157316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    }
158316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen
159316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    /** Gets whether the drag is in process. */
160316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    public boolean getInDragging() {
161316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        return mInDragging;
162316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    }
163316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen
164316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    /**
165dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * Sets the column indices for expected {@link Cursor}
166dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * based on {@link DisplayType}.
167dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     */
168dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    protected void bindColumnIndices() {
169dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mIdIndex = ContactTileLoaderFactory.CONTACT_ID;
170dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mLookupIndex = ContactTileLoaderFactory.LOOKUP_KEY;
171dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mPhotoUriIndex = ContactTileLoaderFactory.PHOTO_URI;
172dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mNameIndex = ContactTileLoaderFactory.DISPLAY_NAME;
173dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mStarredIndex = ContactTileLoaderFactory.STARRED;
174dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mPresenceIndex = ContactTileLoaderFactory.CONTACT_PRESENCE;
175dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mStatusIndex = ContactTileLoaderFactory.CONTACT_STATUS;
176dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
177dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mPhoneNumberIndex = ContactTileLoaderFactory.PHONE_NUMBER;
178dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mPhoneNumberTypeIndex = ContactTileLoaderFactory.PHONE_NUMBER_TYPE;
179dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mPhoneNumberLabelIndex = ContactTileLoaderFactory.PHONE_NUMBER_LABEL;
180dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
181dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
182dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    /**
183dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * Gets the number of frequents from the passed in cursor.
184dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     *
185dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * This methods is needed so the GroupMemberTileAdapter can override this.
186dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     *
187dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * @param cursor The cursor to get number of frequents from.
188dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     */
189dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    protected void saveNumFrequentsFromCursor(Cursor cursor) {
1906a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee        mNumFrequents = cursor.getCount() - mNumStarred;
191dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
192dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
193dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    /**
194dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * Creates {@link ContactTileView}s for each item in {@link Cursor}.
195dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     *
196dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * Else use {@link ContactTileLoaderFactory}
197dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     */
198dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public void setContactCursor(Cursor cursor) {
199316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        if (cursor != null && !cursor.isClosed()) {
200316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            mNumStarred = getNumStarredContacts(cursor);
201316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            saveNumFrequentsFromCursor(cursor);
202316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            saveCursorToCache(cursor);
203dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
204316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            // cause a refresh of any views that rely on this data
205316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            notifyDataSetChanged();
206316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        }
207316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    }
208dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
209316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    /**
210316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     * Saves the cursor data to the cache, to speed up UI changes.
211316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     *
212316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     * @param cursor Returned cursor with data to populate the view.
213316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     */
214316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    private void saveCursorToCache(Cursor cursor) {
215316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        mContactEntries.clear();
216316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        try {
217316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            cursor.moveToPosition(-1);
218316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            while (cursor.moveToNext()) {
219316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                final long id = cursor.getLong(mIdIndex);
220316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                final String photoUri = cursor.getString(mPhotoUriIndex);
221316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                final String lookupKey = cursor.getString(mLookupIndex);
222316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen
223316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                final ContactEntry contact = new ContactEntry();
224316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                final String name = cursor.getString(mNameIndex);
225316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                contact.name = (name != null) ? name : mResources.getString(R.string.missing_name);
226316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                contact.status = cursor.getString(mStatusIndex);
227316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                contact.photoUri = (photoUri != null ? Uri.parse(photoUri) : null);
228316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                contact.lookupKey = ContentUris.withAppendedId(
229316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                        Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey), id);
230316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen
231316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                // Set phone number and label
232316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                final int phoneNumberType = cursor.getInt(mPhoneNumberTypeIndex);
233316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                final String phoneNumberCustomLabel = cursor.getString(mPhoneNumberLabelIndex);
234316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                contact.phoneLabel = (String) Phone.getTypeLabel(mResources, phoneNumberType,
235316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                        phoneNumberCustomLabel);
236316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                contact.phoneNumber = cursor.getString(mPhoneNumberIndex);
237316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                mContactEntries.add(contact);
238316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            }
239316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        } finally {
240316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            cursor.close();
241316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        }
242dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
243dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
244dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    /**
245dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * Iterates over the {@link Cursor}
246dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * Returns position of the first NON Starred Contact
247dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * Returns -1 if {@link DisplayType#STARRED_ONLY}
248dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * Returns 0 if {@link DisplayType#FREQUENT_ONLY}
249dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     */
2506a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee    protected int getNumStarredContacts(Cursor cursor) {
251dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        cursor.moveToPosition(-1);
252dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        while (cursor.moveToNext()) {
253dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            if (cursor.getInt(mStarredIndex) == 0) {
254dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                return cursor.getPosition();
255dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            }
256dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        }
257dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
258dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        // There are not NON Starred contacts in cursor
259dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        // Set divider positon to end
260dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        return cursor.getCount();
261dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
262dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
263316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    /**
264316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     * Loads a contact from the cached list.
265316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     *
266316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     * @param position Position of the Contact.
267316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     * @return Contact at the requested position.
268316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     */
269316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    protected ContactEntry getContactEntryFromCache(int position) {
270316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        if (mContactEntries.size() <= position) return null;
271316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        return mContactEntries.get(position);
272dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
273dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
274dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    /**
275dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * Returns the number of frequents that will be displayed in the list.
276dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     */
277dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public int getNumFrequents() {
278dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        return mNumFrequents;
279dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
280dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
281dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    @Override
282dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public int getCount() {
283316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        if (mContactEntries == null) {
284dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            return 0;
285dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        }
286dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
2876091473941d277ed3746143c1ca9bffdfbe2bd94Christine Chen        int total = mNumFrequents + mNumStarred;
2886091473941d277ed3746143c1ca9bffdfbe2bd94Christine Chen
2896a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee        return total - (mMaxTiledRows * (mColumnCount - 1));
290dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
291dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
2925fe874fbdfe0010b5f2439cf6c13eaee46d406eaYorke Lee    public int getMaxTiledRows() {
2935fe874fbdfe0010b5f2439cf6c13eaee46d406eaYorke Lee        return mMaxTiledRows;
2945fe874fbdfe0010b5f2439cf6c13eaee46d406eaYorke Lee    }
2955fe874fbdfe0010b5f2439cf6c13eaee46d406eaYorke Lee
296dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    /**
297dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * Returns the number of rows required to show the provided number of entries
298dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * with the current number of columns.
299dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     */
300dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    protected int getRowCount(int entryCount) {
301dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        if (entryCount == 0) return 0;
302dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        final int nonLimitedRows = ((entryCount - 1) / mColumnCount) + 1;
3036a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee        return Math.min(mMaxTiledRows, nonLimitedRows);
3046a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee    }
3056a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee
3066a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee    private int getMaxContactsInTiles() {
3076a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee        return mColumnCount * mMaxTiledRows;
308dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
309dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
310316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    protected int getRowIndex(int entryIndex) {
311316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        if (entryIndex < mMaxTiledRows * mColumnCount) {
312316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            return entryIndex / mColumnCount;
313316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        } else {
314316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            return entryIndex - mMaxTiledRows * mColumnCount + mMaxTiledRows;
315316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        }
316316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    }
317316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen
318dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public int getColumnCount() {
319dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        return mColumnCount;
320dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
321dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
322dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    /**
323dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * Returns an ArrayList of the {@link ContactEntry}s that are to appear
324dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * on the row for the given position.
325dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     */
326dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    @Override
327dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public ArrayList<ContactEntry> getItem(int position) {
328dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        ArrayList<ContactEntry> resultList = new ArrayList<ContactEntry>(mColumnCount);
329dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        int contactIndex = position * mColumnCount;
3306a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee        final int maxContactsInTiles = getMaxContactsInTiles();
3316a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee        if (position < getRowCount(maxContactsInTiles)) {
3326a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee            // Contacts that appear as tiles
333dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            for (int columnCounter = 0; columnCounter < mColumnCount &&
3346a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee                    contactIndex != maxContactsInTiles; columnCounter++) {
335316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                resultList.add(getContactEntryFromCache(contactIndex));
336dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                contactIndex++;
337dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            }
338dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        } else {
3396a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee            // Contacts that appear as rows
3406a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee            // The actual position of the contact in the cursor is simply total the number of
3416a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee            // tiled contacts + the given position
3426a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee            contactIndex = maxContactsInTiles + position - 1;
343316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            resultList.add(getContactEntryFromCache(contactIndex));
344dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        }
3456a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee
346dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        return resultList;
347dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
348dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
349dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    @Override
350dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public long getItemId(int position) {
351dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        // As we show several selectable items for each ListView row,
352dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        // we can not determine a stable id. But as we don't rely on ListView's selection,
353dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        // this should not be a problem.
354dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        return position;
355dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
356dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
357dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    @Override
358dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public boolean areAllItemsEnabled() {
359dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        // No dividers, so all items are enabled.
360dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        return true;
361dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
362dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
363dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    @Override
364dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public boolean isEnabled(int position) {
3656a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee        return true;
366dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
367dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
368dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    @Override
369316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    public void notifyDataSetChanged() {
370316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        if (DEBUG) {
371316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            Log.v(TAG, "nofigyDataSetChanged");
372316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        }
373316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        super.notifyDataSetChanged();
374316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    }
375316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen
376316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    /**
377316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     * Configures the animation for each view.
378316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     *
379316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     * @param contactTileRowView The row to be animated.
380316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     * @param position The position of the row.
381316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     * @param itemViewType The type of the row.
382316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     */
383316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    private void configureAnimationToView(ContactTileRow contactTileRowView, int position,
384316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            int itemViewType) {
385316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        if (mInDragging) {
386316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            // If the one item above the row is being dragged, animates all following items to
387316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            // move up. If the item is a favorite tile, animate it to appear from right.
388316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            if (position >= getRowIndex(mDraggedEntryIndex)) {
389316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                if (itemViewType == ViewTypes.FREQUENT) {
390316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                    mTranslateVerticalAnimation.setTarget(contactTileRowView);
391316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                    mTranslateVerticalAnimation.setFloatValues(contactTileRowView.getHeight(), 0);
392316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                    mTranslateVerticalAnimation.clone().start();
393316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                } else {
394316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                    contactTileRowView.animateTilesAppearLeft(mDraggedEntryIndex -
395316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                            position * mColumnCount);
396316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                }
397316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            }
398316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        } else if (mDropEntryIndex != -1) {
399316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            // If one item is dropped in front the row, animate all following rows to shift down.
400316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            // If the item is a favorite tile, animate it to appear from left.
401316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            if (position >= getRowIndex(mDropEntryIndex)) {
402316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                if (itemViewType == ViewTypes.FREQUENT) {
403316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                    if (position == getRowIndex(mDropEntryIndex) || position == mMaxTiledRows) {
404316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                        contactTileRowView.setVisibility(View.VISIBLE);
405316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                        mAlphaAnimation.setTarget(contactTileRowView);
406316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                        mAlphaAnimation.clone().start();
407316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                    } else {
408316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                        mTranslateVerticalAnimation.setTarget(contactTileRowView);
409316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                        mTranslateVerticalAnimation.setFloatValues(-contactTileRowView.getHeight(),
410316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                                0);
411316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                        mTranslateVerticalAnimation.clone().start();
412316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                    }
413316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                } else {
414316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                    contactTileRowView.animateTilesAppearRight(mDropEntryIndex + 1 -
415316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                            position * mColumnCount);
416316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                }
417316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            }
418316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        } else if (mPotentialRemoveEntryIndex != -1) {
419316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            // If one item is to be removed above this row, animate the row to shift up. If it is
420316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            // a favorite contact tile, animate it to appear from right.
421316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            if (position >= getRowIndex(mPotentialRemoveEntryIndex)) {
422316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                if (itemViewType == ViewTypes.FREQUENT) {
423316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                    mTranslateVerticalAnimation.setTarget(contactTileRowView);
424316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                    mTranslateVerticalAnimation.setFloatValues(contactTileRowView.getHeight(), 0);
425316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                    mTranslateVerticalAnimation.clone().start();
426316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                } else {
427316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                    contactTileRowView.animateTilesAppearLeft(
428316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                            mPotentialRemoveEntryIndex - position * mColumnCount);
429316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                }
430316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            }
431316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        }
432316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    }
433316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen
434316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    @Override
435dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public View getView(int position, View convertView, ViewGroup parent) {
43655d3bb4a7f70d4a4359c31b3240f5740b788e643Yorke Lee        if (DEBUG) {
43755d3bb4a7f70d4a4359c31b3240f5740b788e643Yorke Lee            Log.v(TAG, "get view for " + String.valueOf(position));
43855d3bb4a7f70d4a4359c31b3240f5740b788e643Yorke Lee        }
439dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        int itemViewType = getItemViewType(position);
440dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
4416091473941d277ed3746143c1ca9bffdfbe2bd94Christine Chen        ContactTileRow contactTileRowView  = (ContactTileRow) convertView;
4426091473941d277ed3746143c1ca9bffdfbe2bd94Christine Chen
443dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        ArrayList<ContactEntry> contactList = getItem(position);
444dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
445dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        if (contactTileRowView == null) {
446dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            // Creating new row if needed
447316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            contactTileRowView = new ContactTileRow(mContext, itemViewType, position);
448dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        }
449dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
450316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        contactTileRowView.configureRow(contactList, position, position == getCount() - 1);
451316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen
452316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        configureAnimationToView(contactTileRowView, position, itemViewType);
453316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen
454dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        return contactTileRowView;
455dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
456dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
457dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    private int getLayoutResourceId(int viewType) {
458dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        switch (viewType) {
459dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            case ViewTypes.FREQUENT:
460dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                return R.layout.phone_favorite_regular_row_view;
461d99993213962df64c9d76005df86c2fb83fca074Yorke Lee            case ViewTypes.TOP:
462dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                return R.layout.phone_favorite_tile_view;
463dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            default:
464dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                throw new IllegalArgumentException("Unrecognized viewType " + viewType);
465dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        }
466dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
467dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    @Override
468dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public int getViewTypeCount() {
469dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        return ViewTypes.COUNT;
470dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
471dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
472dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    @Override
473dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public int getItemViewType(int position) {
4746a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee        if (position < getRowCount(getMaxContactsInTiles())) {
475d99993213962df64c9d76005df86c2fb83fca074Yorke Lee            return ViewTypes.TOP;
476dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        } else {
477dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            return ViewTypes.FREQUENT;
478dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        }
479dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
480dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
481dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    /**
482dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * Returns the "frequent header" position. Only available when STREQUENT or
483dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * STREQUENT_PHONE_ONLY is used for its display type.
4846a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee     *
4856a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee     * TODO krelease: We shouldn't need this method once we get rid of the frequent header
4866a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee     * in the merged adapter
487dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     */
488dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public int getFrequentHeaderPosition() {
4896a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee        return getRowCount(mNumStarred);
490dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
491dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
492dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    /**
493316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     * Temporarily removes a contact from the list for UI refresh. Stores data for this contact
494316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     * in the back-up variable.
495316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     *
496316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     * @param index Position of the contact to be removed.
497316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     */
498316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    public void popContactEntry(int index) {
499316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        if (index >= 0 && index < mContactEntries.size()) {
500316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            mDraggedEntry = mContactEntries.get(index);
501316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            mDraggedEntryIndex = index;
502316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            mContactEntries.remove(index);
503316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            notifyDataSetChanged();
504316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        }
505316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    }
506316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen
507316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    /**
508316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     * Drops the temporarily removed contact to the desired location in the list.
509316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     *
510316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     * @param index Location where the contact will be dropped.
511316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     */
512316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    public void dropContactEntry(int index) {
513316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        if (mDraggedEntry != null) {
514316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            if (index >= 0 && index <= mContactEntries.size()) {
515316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                mContactEntries.add(index, mDraggedEntry);
516316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                mDropEntryIndex = index;
517316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            } else if (mDraggedEntryIndex >= 0 && mDraggedEntryIndex <= mContactEntries.size()) {
518316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                /** If the index is invalid, falls back to the original position of the contact. */
519316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                mContactEntries.add(mDraggedEntryIndex, mDraggedEntry);
520316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                mDropEntryIndex = mDraggedEntryIndex;
521316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            }
522316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            mDraggedEntry = null;
523316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            notifyDataSetChanged();
524316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        }
525316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    }
526316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen
527316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    /**
528316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     * Sets an item to for pending removal. If the user does not click the undo button, the item
529316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     * will be removed at the next interaction.
530316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     *
531316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     * @param index Index of the item to be removed.
532316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     */
533316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    public void setPotentialRemoveEntryIndex(int index) {
534316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        mPotentialRemoveEntryIndex = index;
535316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    }
536316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen
537316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    /**
538316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     * Removes a contact entry from the cache.
539316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     *
540316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     * @return True is an item is removed. False is there is no item to be removed.
541316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     */
542316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    public boolean removeContactEntry() {
543316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        if (mPotentialRemoveEntryIndex >= 0 && mPotentialRemoveEntryIndex < mContactEntries.size()) {
544316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            mContactEntries.remove(mPotentialRemoveEntryIndex);
545316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            notifyDataSetChanged();
546316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            return true;
547316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        }
548316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        return false;
549316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    }
550316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen
551316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    /**
552316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     * Resets the item for pending removal.
553316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     */
554316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    public void undoPotentialRemoveEntryIndex() {
555316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        mPotentialRemoveEntryIndex = -1;
556316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    }
557316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen
558316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    /**
559316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     * Clears all temporary variables at a new interaction.
560316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen     */
561316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    public void cleanTempVariables() {
562316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        mDraggedEntryIndex = -1;
563316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        mDropEntryIndex = -1;
564316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        mDraggedEntry = null;
565316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        mPotentialRemoveEntryIndex = -1;
566316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    }
567316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen
568316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    /**
569dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * Acts as a row item composed of {@link ContactTileView}
570dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     *
571dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * TODO: FREQUENT doesn't really need it.  Just let {@link #getView} return
572dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     */
573316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen    public class ContactTileRow extends FrameLayout {
574dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        private int mItemViewType;
575dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        private int mLayoutResId;
576d99993213962df64c9d76005df86c2fb83fca074Yorke Lee        private final int mRowPaddingStart;
577d99993213962df64c9d76005df86c2fb83fca074Yorke Lee        private final int mRowPaddingEnd;
578d99993213962df64c9d76005df86c2fb83fca074Yorke Lee        private final int mRowPaddingTop;
579d99993213962df64c9d76005df86c2fb83fca074Yorke Lee        private final int mRowPaddingBottom;
580316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        private int mPosition;
581dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
582316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        public ContactTileRow(Context context, int itemViewType, int position) {
583dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            super(context);
584dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            mItemViewType = itemViewType;
585dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            mLayoutResId = getLayoutResourceId(mItemViewType);
586316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            mPosition = position;
587dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
588d99993213962df64c9d76005df86c2fb83fca074Yorke Lee            final Resources resources = mContext.getResources();
589d99993213962df64c9d76005df86c2fb83fca074Yorke Lee            mRowPaddingStart = resources.getDimensionPixelSize(
590d99993213962df64c9d76005df86c2fb83fca074Yorke Lee                    R.dimen.favorites_row_start_padding);
591d99993213962df64c9d76005df86c2fb83fca074Yorke Lee            mRowPaddingEnd = resources.getDimensionPixelSize(
592d99993213962df64c9d76005df86c2fb83fca074Yorke Lee                    R.dimen.favorites_row_end_padding);
593d99993213962df64c9d76005df86c2fb83fca074Yorke Lee            mRowPaddingTop = resources.getDimensionPixelSize(
594d99993213962df64c9d76005df86c2fb83fca074Yorke Lee                    R.dimen.favorites_row_top_padding);
595d99993213962df64c9d76005df86c2fb83fca074Yorke Lee            mRowPaddingBottom = resources.getDimensionPixelSize(
596d99993213962df64c9d76005df86c2fb83fca074Yorke Lee                    R.dimen.favorites_row_bottom_padding);
597d99993213962df64c9d76005df86c2fb83fca074Yorke Lee
598d99993213962df64c9d76005df86c2fb83fca074Yorke Lee            setBackgroundResource(R.drawable.bottom_border_background);
599d99993213962df64c9d76005df86c2fb83fca074Yorke Lee
600d99993213962df64c9d76005df86c2fb83fca074Yorke Lee            setPaddingRelative(mRowPaddingStart, mRowPaddingTop, mRowPaddingEnd,
601d99993213962df64c9d76005df86c2fb83fca074Yorke Lee                    mRowPaddingBottom);
602d99993213962df64c9d76005df86c2fb83fca074Yorke Lee
603dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            // Remove row (but not children) from accessibility node tree.
604dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
605dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        }
606dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
607dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        /**
608dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee         * Configures the row to add {@link ContactEntry}s information to the views
609dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee         */
610316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        public void configureRow(ArrayList<ContactEntry> list, int position, boolean isLastRow) {
611dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            int columnCount = mItemViewType == ViewTypes.FREQUENT ? 1 : mColumnCount;
612316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            mPosition = position;
613dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
614dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            // Adding tiles to row and filling in contact information
615dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            for (int columnCounter = 0; columnCounter < columnCount; columnCounter++) {
616dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                ContactEntry entry =
617dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                        columnCounter < list.size() ? list.get(columnCounter) : null;
618dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                addTileFromEntry(entry, columnCounter, isLastRow);
619dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            }
620dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        }
621dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
622dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        private void addTileFromEntry(ContactEntry entry, int childIndex, boolean isLastRow) {
623316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            final PhoneFavoriteTileView contactTile;
624dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
625dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            if (getChildCount() <= childIndex) {
626dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
627316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                contactTile = (PhoneFavoriteTileView) inflate(mContext, mLayoutResId, null);
628dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                // Note: the layoutparam set here is only actually used for FREQUENT.
629dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                // We override onMeasure() for STARRED and we don't care the layout param there.
630d99993213962df64c9d76005df86c2fb83fca074Yorke Lee                final Resources resources = mContext.getResources();
631dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
632dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                        ViewGroup.LayoutParams.WRAP_CONTENT,
633dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                        ViewGroup.LayoutParams.WRAP_CONTENT);
634dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
635dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                params.setMargins(
636316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                        resources.getDimensionPixelSize(R.dimen.detail_item_side_margin), 0,
637316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                        resources.getDimensionPixelSize(R.dimen.detail_item_side_margin), 0);
638dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                contactTile.setLayoutParams(params);
639dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                contactTile.setPhotoManager(mPhotoManager);
640dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                contactTile.setListener(mListener);
641dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                addView(contactTile);
642dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            } else {
643316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                contactTile = (PhoneFavoriteTileView) getChildAt(childIndex);
644dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            }
645dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            contactTile.loadFromContact(entry);
646316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            contactTile.setId(childIndex);
647dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            switch (mItemViewType) {
648d99993213962df64c9d76005df86c2fb83fca074Yorke Lee                case ViewTypes.TOP:
649dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                    // Setting divider visibilities
650dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                    contactTile.setPaddingRelative(0, 0,
651d99993213962df64c9d76005df86c2fb83fca074Yorke Lee                            childIndex >= mColumnCount - 1 ? 0 : mPaddingInPixels, 0);
652dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                    break;
653dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                case ViewTypes.FREQUENT:
654dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                    contactTile.setHorizontalDividerVisibility(
655dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                            isLastRow ? View.GONE : View.VISIBLE);
656dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                    break;
657dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                default:
658dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                    break;
659dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            }
660316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            contactTile.setupFavoriteContactCard();
661dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        }
662dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
663dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        @Override
664dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
665dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            switch (mItemViewType) {
666d99993213962df64c9d76005df86c2fb83fca074Yorke Lee                case ViewTypes.TOP:
667dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                    onLayoutForTiles();
668dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                    return;
669dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                default:
670dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                    super.onLayout(changed, left, top, right, bottom);
671dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                    return;
672dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            }
673dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        }
674dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
675dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        private void onLayoutForTiles() {
676dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            final int count = getChildCount();
677dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
678dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            // Just line up children horizontally.
679d99993213962df64c9d76005df86c2fb83fca074Yorke Lee            int childLeft = getPaddingStart();
680dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            for (int i = 0; i < count; i++) {
681dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                final View child = getChildAt(i);
682dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
683dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                // Note MeasuredWidth includes the padding.
684dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                final int childWidth = child.getMeasuredWidth();
685dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                child.layout(childLeft, 0, childLeft + childWidth, child.getMeasuredHeight());
686dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                childLeft += childWidth;
687dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            }
688dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        }
689dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
690dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        @Override
691dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
692dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            switch (mItemViewType) {
693d99993213962df64c9d76005df86c2fb83fca074Yorke Lee                case ViewTypes.TOP:
694dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                    onMeasureForTiles(widthMeasureSpec);
695dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                    return;
696dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                default:
697dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
698dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                    return;
699dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            }
700dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        }
701dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
702dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        private void onMeasureForTiles(int widthMeasureSpec) {
703dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            final int width = MeasureSpec.getSize(widthMeasureSpec);
704dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
705dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            final int childCount = getChildCount();
706dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            if (childCount == 0) {
707dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                // Just in case...
708dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                setMeasuredDimension(width, 0);
709dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                return;
710dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            }
711dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
712dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            // 1. Calculate image size.
713dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            //      = ([total width] - [total padding]) / [child count]
714dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            //
715dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            // 2. Set it to width/height of each children.
716dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            //    If we have a remainder, some tiles will have 1 pixel larger width than its height.
717dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            //
718dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            // 3. Set the dimensions of itself.
719dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            //    Let width = given width.
720dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            //    Let height = image size + bottom paddding.
721dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
722d99993213962df64c9d76005df86c2fb83fca074Yorke Lee            final int totalPaddingsInPixels = (mColumnCount - 1) * mPaddingInPixels
723d99993213962df64c9d76005df86c2fb83fca074Yorke Lee                    + mRowPaddingStart + mRowPaddingEnd;
724dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
725dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            // Preferred width / height for images (excluding the padding).
726dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            // The actual width may be 1 pixel larger than this if we have a remainder.
727dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            final int imageSize = (width - totalPaddingsInPixels) / mColumnCount;
728dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            final int remainder = width - (imageSize * mColumnCount) - totalPaddingsInPixels;
729dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
730dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            for (int i = 0; i < childCount; i++) {
731dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                final View child = getChildAt(i);
732dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                final int childWidth = imageSize + child.getPaddingRight()
733dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                        // Compensate for the remainder
734dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                        + (i < remainder ? 1 : 0);
735d99993213962df64c9d76005df86c2fb83fca074Yorke Lee                final int childHeight = imageSize;
736dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                child.measure(
737dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                        MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY),
738dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                        MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY)
739dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                        );
740dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            }
741d99993213962df64c9d76005df86c2fb83fca074Yorke Lee            setMeasuredDimension(width, imageSize + getPaddingTop() + getPaddingBottom());
742dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        }
743316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen
744316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        /**
745316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen         * Gets the index of the item at the specified coordinates.
746316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen         *
747316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen         * @param itemX X-coordinate of the selected item.
748316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen         * @param itemY Y-coordinate of the selected item.
749316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen         * @return Index of the selected item in the cached array.
750316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen         */
751316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        public int getItemIndex(float itemX, float itemY) {
752316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            if (mPosition < mMaxTiledRows) {
753316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                final Rect childRect = new Rect();
754316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                if (DEBUG) {
755316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                    Log.v(TAG, String.valueOf(itemX) + " " + String.valueOf(itemY));
756316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                }
757316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                for (int i = 0; i < getChildCount(); ++i) {
758316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                    /** If the row contains multiple tiles, checks each tile to see if the point
759316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                     * is contained in the tile. */
760316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                    getChildAt(i).getHitRect(childRect);
761316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                    if (DEBUG) {
762316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                        Log.v(TAG, childRect.toString());
763316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                    }
764316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                    if (childRect.contains((int)itemX, (int)itemY)) {
765316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                        /** If the point is contained in the rectangle, computes the index of the
766316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                         * item in the cached array. */
767316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                        return i + (mPosition) * mColumnCount;
768316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                    }
769316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                }
770316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            } else {
771316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                /** If the selected item is one of the rows, compute the index. */
772316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                return (mPosition - mMaxTiledRows) + mColumnCount * mMaxTiledRows;
773316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            }
774316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            return -1;
775316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        }
776316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen
777316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        public PhoneFavoritesTileAdapter getTileAdapter() {
778316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            return PhoneFavoritesTileAdapter.this;
779316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        }
780316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen
781316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        public void animateTilesAppearLeft(int index) {
782316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            for (int i = index; i < getChildCount(); ++i) {
783316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                View childView = getChildAt(i);
784316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                mTranslateHorizontalAnimation.setTarget(childView);
785316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                mTranslateHorizontalAnimation.setFloatValues(childView.getWidth(), 0);
786316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                mTranslateHorizontalAnimation.clone().start();
787316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            }
788316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        }
789316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen
790316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        public void animateTilesAppearRight(int index) {
791316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            for (int i = index; i < getChildCount(); ++i) {
792316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                View childView = getChildAt(i);
793316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                mTranslateHorizontalAnimation.setTarget(childView);
794316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                mTranslateHorizontalAnimation.setFloatValues(-childView.getWidth(), 0);
795316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen                mTranslateHorizontalAnimation.clone().start();
796316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            }
797316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        }
798316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen
799316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        public int getPosition() {
800316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen            return mPosition;
801316b4713b2f8f26f393ecc4bb4760512a4a9f096Christine Chen        }
802dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
803dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
804dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    protected static class ViewTypes {
805d99993213962df64c9d76005df86c2fb83fca074Yorke Lee        public static final int COUNT = 2;
806d99993213962df64c9d76005df86c2fb83fca074Yorke Lee        public static final int FREQUENT = 0;
807d99993213962df64c9d76005df86c2fb83fca074Yorke Lee        public static final int TOP = 1;
808dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
809dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee}
810