PhoneFavoritesTileAdapter.java revision 6a8402939f667ab70bd0043ed0859f8afbc012ec
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
18dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.content.ContentUris;
19dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.content.Context;
20dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.content.res.Resources;
21dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.database.Cursor;
22dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.graphics.drawable.Drawable;
23dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.net.Uri;
24dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.provider.ContactsContract.CommonDataKinds.Phone;
25dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.provider.ContactsContract.Contacts;
26dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.util.Log;
27dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.view.View;
28dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.view.ViewGroup;
29dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.widget.BaseAdapter;
30dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport android.widget.FrameLayout;
31dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
32dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport com.android.contacts.common.ContactPhotoManager;
33dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport com.android.contacts.common.ContactTileLoaderFactory;
34dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport com.android.contacts.common.R;
35dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport com.android.contacts.common.list.ContactEntry;
36dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport com.android.contacts.common.list.ContactTileAdapter;
37dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport com.android.contacts.common.list.ContactTileView;
38dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
39dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leeimport java.util.ArrayList;
40dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
41dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee/**
42dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * Also allows for a configurable number of columns as well as a maximum row of tiled contacts.
43dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee *
44dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee * This adapter has been rewritten to only support a maximum of one row for favorites.
45dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee *
46dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee */
47dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Leepublic class PhoneFavoritesTileAdapter extends BaseAdapter {
48dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    private static final String TAG = ContactTileAdapter.class.getSimpleName();
49dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
506a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee    public static final int ROW_LIMIT_DEFAULT = 1;
51dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
52dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    private ContactTileView.Listener mListener;
53dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    private Context mContext;
54dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    private Resources mResources;
55dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    protected Cursor mContactCursor = null;
56dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    private ContactPhotoManager mPhotoManager;
57dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    protected int mNumFrequents;
586a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee    protected int mNumStarred;
59dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
60dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    protected int mColumnCount;
616a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee    private int mMaxTiledRows = ROW_LIMIT_DEFAULT;
62dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    private int mStarredIndex;
63dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
64dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    protected int mIdIndex;
65dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    protected int mLookupIndex;
66dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    protected int mPhotoUriIndex;
67dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    protected int mNameIndex;
68dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    protected int mPresenceIndex;
69dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    protected int mStatusIndex;
70dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
71dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    /**
72dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * Only valid when {@link DisplayType#STREQUENT_PHONE_ONLY} is true
73dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     */
74dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    private int mPhoneNumberIndex;
75dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    private int mPhoneNumberTypeIndex;
76dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    private int mPhoneNumberLabelIndex;
77dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
78dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    private boolean mIsQuickContactEnabled = false;
79dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    private final int mPaddingInPixels;
80dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
81dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public PhoneFavoritesTileAdapter(Context context, ContactTileView.Listener listener, int numCols) {
826a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee        this(context, listener, numCols, ROW_LIMIT_DEFAULT);
83dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
84dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
85dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public PhoneFavoritesTileAdapter(Context context, ContactTileView.Listener listener, int numCols,
86dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            int maxTiledRows) {
87dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mListener = listener;
88dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mContext = context;
89dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mResources = context.getResources();
90dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mColumnCount = numCols;
91dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mNumFrequents = 0;
92dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mMaxTiledRows = maxTiledRows;
93dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
94dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        // Converting padding in dips to padding in pixels
95dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mPaddingInPixels = mContext.getResources()
96d99993213962df64c9d76005df86c2fb83fca074Yorke Lee                .getDimensionPixelSize(R.dimen.phone_contact_tile_divider_padding);
97dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        bindColumnIndices();
98dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
99dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
100dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public void setPhotoLoader(ContactPhotoManager photoLoader) {
101dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mPhotoManager = photoLoader;
102dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
103dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
104dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public void setMaxRowCount(int maxRows) {
105dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mMaxTiledRows = maxRows;
106dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
107dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
108dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public void setColumnCount(int columnCount) {
109dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mColumnCount = columnCount;
110dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
111dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
112dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public void enableQuickContact(boolean enableQuickContact) {
113dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mIsQuickContactEnabled = enableQuickContact;
114dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
115dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
116dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    /**
117dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * Sets the column indices for expected {@link Cursor}
118dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * based on {@link DisplayType}.
119dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     */
120dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    protected void bindColumnIndices() {
121dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mIdIndex = ContactTileLoaderFactory.CONTACT_ID;
122dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mLookupIndex = ContactTileLoaderFactory.LOOKUP_KEY;
123dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mPhotoUriIndex = ContactTileLoaderFactory.PHOTO_URI;
124dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mNameIndex = ContactTileLoaderFactory.DISPLAY_NAME;
125dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mStarredIndex = ContactTileLoaderFactory.STARRED;
126dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mPresenceIndex = ContactTileLoaderFactory.CONTACT_PRESENCE;
127dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mStatusIndex = ContactTileLoaderFactory.CONTACT_STATUS;
128dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
129dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mPhoneNumberIndex = ContactTileLoaderFactory.PHONE_NUMBER;
130dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mPhoneNumberTypeIndex = ContactTileLoaderFactory.PHONE_NUMBER_TYPE;
131dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mPhoneNumberLabelIndex = ContactTileLoaderFactory.PHONE_NUMBER_LABEL;
132dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
133dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
134dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    /**
135dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * Gets the number of frequents from the passed in cursor.
136dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     *
137dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * This methods is needed so the GroupMemberTileAdapter can override this.
138dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     *
139dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * @param cursor The cursor to get number of frequents from.
140dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     */
141dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    protected void saveNumFrequentsFromCursor(Cursor cursor) {
1426a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee        mNumFrequents = cursor.getCount() - mNumStarred;
143dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
144dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
145dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    /**
146dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * Creates {@link ContactTileView}s for each item in {@link Cursor}.
147dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     *
148dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * Else use {@link ContactTileLoaderFactory}
149dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     */
150dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public void setContactCursor(Cursor cursor) {
151dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        mContactCursor = cursor;
1526a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee        mNumStarred = getNumStarredContacts(cursor);
153dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
154dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        saveNumFrequentsFromCursor(cursor);
155dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
156dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        // cause a refresh of any views that rely on this data
157dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        notifyDataSetChanged();
158dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
159dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
160dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    /**
161dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * Iterates over the {@link Cursor}
162dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * Returns position of the first NON Starred Contact
163dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * Returns -1 if {@link DisplayType#STARRED_ONLY}
164dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * Returns 0 if {@link DisplayType#FREQUENT_ONLY}
165dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     */
1666a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee    protected int getNumStarredContacts(Cursor cursor) {
167dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        if (cursor == null || cursor.isClosed()) {
168dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            throw new IllegalStateException("Unable to access cursor");
169dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        }
170dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
171dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        cursor.moveToPosition(-1);
172dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        while (cursor.moveToNext()) {
173dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            if (cursor.getInt(mStarredIndex) == 0) {
174dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                return cursor.getPosition();
175dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            }
176dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        }
177dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
178dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        // There are not NON Starred contacts in cursor
179dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        // Set divider positon to end
180dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        return cursor.getCount();
181dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
182dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
183dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    protected ContactEntry createContactEntryFromCursor(Cursor cursor, int position) {
184dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        // If the loader was canceled we will be given a null cursor.
185dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        // In that case, show an empty list of contacts.
186dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        if (cursor == null || cursor.isClosed() || cursor.getCount() <= position) return null;
187dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
188dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        cursor.moveToPosition(position);
189dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        long id = cursor.getLong(mIdIndex);
190dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        String photoUri = cursor.getString(mPhotoUriIndex);
191dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        String lookupKey = cursor.getString(mLookupIndex);
192dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
193dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        ContactEntry contact = new ContactEntry();
194dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        String name = cursor.getString(mNameIndex);
195dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        contact.name = (name != null) ? name : mResources.getString(R.string.missing_name);
196dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        contact.status = cursor.getString(mStatusIndex);
197dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        contact.photoUri = (photoUri != null ? Uri.parse(photoUri) : null);
198dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        contact.lookupKey = ContentUris.withAppendedId(
199dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                Uri.withAppendedPath(Contacts.CONTENT_LOOKUP_URI, lookupKey), id);
200dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
201dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        // Set phone number and label
202dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        int phoneNumberType = cursor.getInt(mPhoneNumberTypeIndex);
203dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        String phoneNumberCustomLabel = cursor.getString(mPhoneNumberLabelIndex);
204dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        contact.phoneLabel = (String) Phone.getTypeLabel(mResources, phoneNumberType,
205dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                phoneNumberCustomLabel);
206dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        contact.phoneNumber = cursor.getString(mPhoneNumberIndex);
207dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
208dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        return contact;
209dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
210dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
211dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    /**
212dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * Returns the number of frequents that will be displayed in the list.
213dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     */
214dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public int getNumFrequents() {
215dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        return mNumFrequents;
216dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
217dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
218dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    @Override
219dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public int getCount() {
220dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        if (mContactCursor == null || mContactCursor.isClosed()) {
221dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            return 0;
222dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        }
223dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
2246a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee        final int total = mNumFrequents + mNumStarred;
2256a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee        return total - (mMaxTiledRows * (mColumnCount - 1));
226dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
227dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
228dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    /**
229dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * Returns the number of rows required to show the provided number of entries
230dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * with the current number of columns.
231dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     */
232dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    protected int getRowCount(int entryCount) {
233dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        if (entryCount == 0) return 0;
234dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        final int nonLimitedRows = ((entryCount - 1) / mColumnCount) + 1;
2356a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee        return Math.min(mMaxTiledRows, nonLimitedRows);
2366a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee    }
2376a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee
2386a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee    private int getMaxContactsInTiles() {
2396a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee        return mColumnCount * mMaxTiledRows;
240dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
241dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
242dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public int getColumnCount() {
243dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        return mColumnCount;
244dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
245dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
246dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    /**
247dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * Returns an ArrayList of the {@link ContactEntry}s that are to appear
248dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * on the row for the given position.
249dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     */
250dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    @Override
251dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public ArrayList<ContactEntry> getItem(int position) {
252dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        ArrayList<ContactEntry> resultList = new ArrayList<ContactEntry>(mColumnCount);
253dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        int contactIndex = position * mColumnCount;
2546a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee        final int maxContactsInTiles = getMaxContactsInTiles();
2556a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee        if (position < getRowCount(maxContactsInTiles)) {
2566a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee            // Contacts that appear as tiles
257dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            for (int columnCounter = 0; columnCounter < mColumnCount &&
2586a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee                    contactIndex != maxContactsInTiles; columnCounter++) {
259dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                resultList.add(createContactEntryFromCursor(mContactCursor, contactIndex));
260dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                contactIndex++;
261dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            }
262dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        } else {
2636a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee            // Contacts that appear as rows
2646a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee            // The actual position of the contact in the cursor is simply total the number of
2656a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee            // tiled contacts + the given position
2666a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee            contactIndex = maxContactsInTiles + position - 1;
267dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            resultList.add(createContactEntryFromCursor(mContactCursor, contactIndex));
268dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        }
2696a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee
270dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        return resultList;
271dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
272dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
273dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    @Override
274dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public long getItemId(int position) {
275dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        // As we show several selectable items for each ListView row,
276dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        // we can not determine a stable id. But as we don't rely on ListView's selection,
277dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        // this should not be a problem.
278dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        return position;
279dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
280dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
281dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    @Override
282dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public boolean areAllItemsEnabled() {
283dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        // No dividers, so all items are enabled.
284dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        return true;
285dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
286dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
287dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    @Override
288dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public boolean isEnabled(int position) {
2896a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee        return true;
290dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
291dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
292dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    @Override
293dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public View getView(int position, View convertView, ViewGroup parent) {
294dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        int itemViewType = getItemViewType(position);
295dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
296dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        ContactTileRow contactTileRowView = (ContactTileRow) convertView;
297dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        ArrayList<ContactEntry> contactList = getItem(position);
298dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
299dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        if (contactTileRowView == null) {
300dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            // Creating new row if needed
301dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            contactTileRowView = new ContactTileRow(mContext, itemViewType);
302dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        }
303dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
304dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        contactTileRowView.configureRow(contactList, position == getCount() - 1);
305dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        return contactTileRowView;
306dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
307dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
308dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    private int getLayoutResourceId(int viewType) {
309dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        switch (viewType) {
310dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            case ViewTypes.FREQUENT:
311dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                return R.layout.phone_favorite_regular_row_view;
312d99993213962df64c9d76005df86c2fb83fca074Yorke Lee            case ViewTypes.TOP:
313dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                return R.layout.phone_favorite_tile_view;
314dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            default:
315dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                throw new IllegalArgumentException("Unrecognized viewType " + viewType);
316dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        }
317dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
318dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    @Override
319dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public int getViewTypeCount() {
320dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        return ViewTypes.COUNT;
321dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
322dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
323dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    @Override
324dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public int getItemViewType(int position) {
3256a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee        if (position < getRowCount(getMaxContactsInTiles())) {
326d99993213962df64c9d76005df86c2fb83fca074Yorke Lee            return ViewTypes.TOP;
327dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        } else {
328dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            return ViewTypes.FREQUENT;
329dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        }
330dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
331dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
332dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    /**
333dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * Returns the "frequent header" position. Only available when STREQUENT or
334dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * STREQUENT_PHONE_ONLY is used for its display type.
3356a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee     *
3366a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee     * TODO krelease: We shouldn't need this method once we get rid of the frequent header
3376a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee     * in the merged adapter
338dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     */
339dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    public int getFrequentHeaderPosition() {
3406a8402939f667ab70bd0043ed0859f8afbc012ecYorke Lee        return getRowCount(mNumStarred);
341dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
342dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
343dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    /**
344dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * Acts as a row item composed of {@link ContactTileView}
345dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     *
346dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     * TODO: FREQUENT doesn't really need it.  Just let {@link #getView} return
347dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee     */
348dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    private class ContactTileRow extends FrameLayout {
349dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        private int mItemViewType;
350dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        private int mLayoutResId;
351d99993213962df64c9d76005df86c2fb83fca074Yorke Lee        private final int mRowPaddingStart;
352d99993213962df64c9d76005df86c2fb83fca074Yorke Lee        private final int mRowPaddingEnd;
353d99993213962df64c9d76005df86c2fb83fca074Yorke Lee        private final int mRowPaddingTop;
354d99993213962df64c9d76005df86c2fb83fca074Yorke Lee        private final int mRowPaddingBottom;
355dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
356dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        public ContactTileRow(Context context, int itemViewType) {
357dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            super(context);
358dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            mItemViewType = itemViewType;
359dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            mLayoutResId = getLayoutResourceId(mItemViewType);
360dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
361d99993213962df64c9d76005df86c2fb83fca074Yorke Lee            final Resources resources = mContext.getResources();
362d99993213962df64c9d76005df86c2fb83fca074Yorke Lee            mRowPaddingStart = resources.getDimensionPixelSize(
363d99993213962df64c9d76005df86c2fb83fca074Yorke Lee                    R.dimen.favorites_row_start_padding);
364d99993213962df64c9d76005df86c2fb83fca074Yorke Lee            mRowPaddingEnd = resources.getDimensionPixelSize(
365d99993213962df64c9d76005df86c2fb83fca074Yorke Lee                    R.dimen.favorites_row_end_padding);
366d99993213962df64c9d76005df86c2fb83fca074Yorke Lee            mRowPaddingTop = resources.getDimensionPixelSize(
367d99993213962df64c9d76005df86c2fb83fca074Yorke Lee                    R.dimen.favorites_row_top_padding);
368d99993213962df64c9d76005df86c2fb83fca074Yorke Lee            mRowPaddingBottom = resources.getDimensionPixelSize(
369d99993213962df64c9d76005df86c2fb83fca074Yorke Lee                    R.dimen.favorites_row_bottom_padding);
370d99993213962df64c9d76005df86c2fb83fca074Yorke Lee
371d99993213962df64c9d76005df86c2fb83fca074Yorke Lee            setBackgroundResource(R.drawable.bottom_border_background);
372d99993213962df64c9d76005df86c2fb83fca074Yorke Lee
373d99993213962df64c9d76005df86c2fb83fca074Yorke Lee            setPaddingRelative(mRowPaddingStart, mRowPaddingTop, mRowPaddingEnd,
374d99993213962df64c9d76005df86c2fb83fca074Yorke Lee                    mRowPaddingBottom);
375d99993213962df64c9d76005df86c2fb83fca074Yorke Lee
376dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            // Remove row (but not children) from accessibility node tree.
377dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
378dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        }
379dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
380dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        /**
381dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee         * Configures the row to add {@link ContactEntry}s information to the views
382dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee         */
383dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        public void configureRow(ArrayList<ContactEntry> list, boolean isLastRow) {
384dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            int columnCount = mItemViewType == ViewTypes.FREQUENT ? 1 : mColumnCount;
385dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
386dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            // Adding tiles to row and filling in contact information
387dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            for (int columnCounter = 0; columnCounter < columnCount; columnCounter++) {
388dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                ContactEntry entry =
389dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                        columnCounter < list.size() ? list.get(columnCounter) : null;
390dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                addTileFromEntry(entry, columnCounter, isLastRow);
391dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            }
392dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        }
393dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
394dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        private void addTileFromEntry(ContactEntry entry, int childIndex, boolean isLastRow) {
395dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            final ContactTileView contactTile;
396dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
397dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            if (getChildCount() <= childIndex) {
398dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
399dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                contactTile = (ContactTileView) inflate(mContext, mLayoutResId, null);
400dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                // Note: the layoutparam set here is only actually used for FREQUENT.
401dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                // We override onMeasure() for STARRED and we don't care the layout param there.
402d99993213962df64c9d76005df86c2fb83fca074Yorke Lee                final Resources resources = mContext.getResources();
403dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
404dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                        ViewGroup.LayoutParams.WRAP_CONTENT,
405dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                        ViewGroup.LayoutParams.WRAP_CONTENT);
406dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
407dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                params.setMargins(
408dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                        resources.getDimensionPixelSize(R.dimen.detail_item_side_margin),
409dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                        0,
410dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                        resources.getDimensionPixelSize(R.dimen.detail_item_side_margin),
411dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                        0);
412dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                contactTile.setLayoutParams(params);
413dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                contactTile.setPhotoManager(mPhotoManager);
414dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                contactTile.setListener(mListener);
415dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                addView(contactTile);
416dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            } else {
417dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                contactTile = (ContactTileView) getChildAt(childIndex);
418dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            }
419dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            contactTile.loadFromContact(entry);
420dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            switch (mItemViewType) {
421d99993213962df64c9d76005df86c2fb83fca074Yorke Lee                case ViewTypes.TOP:
422dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                    // Setting divider visibilities
423dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                    contactTile.setPaddingRelative(0, 0,
424d99993213962df64c9d76005df86c2fb83fca074Yorke Lee                            childIndex >= mColumnCount - 1 ? 0 : mPaddingInPixels, 0);
425dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                    break;
426dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                case ViewTypes.FREQUENT:
427dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                    contactTile.setHorizontalDividerVisibility(
428dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                            isLastRow ? View.GONE : View.VISIBLE);
429dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                    break;
430dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                default:
431dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                    break;
432dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            }
433dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        }
434dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
435dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        @Override
436dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
437dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            switch (mItemViewType) {
438d99993213962df64c9d76005df86c2fb83fca074Yorke Lee                case ViewTypes.TOP:
439dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                    onLayoutForTiles();
440dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                    return;
441dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                default:
442dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                    super.onLayout(changed, left, top, right, bottom);
443dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                    return;
444dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            }
445dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        }
446dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
447dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        private void onLayoutForTiles() {
448dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            final int count = getChildCount();
449dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
450dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            // Just line up children horizontally.
451d99993213962df64c9d76005df86c2fb83fca074Yorke Lee            int childLeft = getPaddingStart();
452dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            for (int i = 0; i < count; i++) {
453dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                final View child = getChildAt(i);
454dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
455dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                // Note MeasuredWidth includes the padding.
456dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                final int childWidth = child.getMeasuredWidth();
457dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                child.layout(childLeft, 0, childLeft + childWidth, child.getMeasuredHeight());
458dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                childLeft += childWidth;
459dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            }
460dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        }
461dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
462dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        @Override
463dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
464dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            switch (mItemViewType) {
465d99993213962df64c9d76005df86c2fb83fca074Yorke Lee                case ViewTypes.TOP:
466dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                    onMeasureForTiles(widthMeasureSpec);
467dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                    return;
468dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                default:
469dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
470dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                    return;
471dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            }
472dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        }
473dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
474dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        private void onMeasureForTiles(int widthMeasureSpec) {
475dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            final int width = MeasureSpec.getSize(widthMeasureSpec);
476dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
477dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            final int childCount = getChildCount();
478dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            if (childCount == 0) {
479dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                // Just in case...
480dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                setMeasuredDimension(width, 0);
481dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                return;
482dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            }
483dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
484dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            // 1. Calculate image size.
485dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            //      = ([total width] - [total padding]) / [child count]
486dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            //
487dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            // 2. Set it to width/height of each children.
488dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            //    If we have a remainder, some tiles will have 1 pixel larger width than its height.
489dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            //
490dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            // 3. Set the dimensions of itself.
491dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            //    Let width = given width.
492dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            //    Let height = image size + bottom paddding.
493dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
494d99993213962df64c9d76005df86c2fb83fca074Yorke Lee            final int totalPaddingsInPixels = (mColumnCount - 1) * mPaddingInPixels
495d99993213962df64c9d76005df86c2fb83fca074Yorke Lee                    + mRowPaddingStart + mRowPaddingEnd;
496dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
497dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            // Preferred width / height for images (excluding the padding).
498dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            // The actual width may be 1 pixel larger than this if we have a remainder.
499dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            final int imageSize = (width - totalPaddingsInPixels) / mColumnCount;
500dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            final int remainder = width - (imageSize * mColumnCount) - totalPaddingsInPixels;
501dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
502dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            for (int i = 0; i < childCount; i++) {
503dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                final View child = getChildAt(i);
504dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                final int childWidth = imageSize + child.getPaddingRight()
505dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                        // Compensate for the remainder
506dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                        + (i < remainder ? 1 : 0);
507d99993213962df64c9d76005df86c2fb83fca074Yorke Lee                final int childHeight = imageSize;
508dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                child.measure(
509dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                        MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY),
510dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                        MeasureSpec.makeMeasureSpec(childHeight, MeasureSpec.EXACTLY)
511dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee                        );
512dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee            }
513d99993213962df64c9d76005df86c2fb83fca074Yorke Lee            setMeasuredDimension(width, imageSize + getPaddingTop() + getPaddingBottom());
514dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee        }
515dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
516dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee
517dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    protected static class ViewTypes {
518d99993213962df64c9d76005df86c2fb83fca074Yorke Lee        public static final int COUNT = 2;
519d99993213962df64c9d76005df86c2fb83fca074Yorke Lee        public static final int FREQUENT = 0;
520d99993213962df64c9d76005df86c2fb83fca074Yorke Lee        public static final int TOP = 1;
521dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee    }
522dfb2eee7d98f8540fd1614db66bb03e8e1f3a26aYorke Lee}
523