1238d9847d8f2ace658fb7337c8847a2088ddc9d1Dmitri Plotnikov/*
232f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaro * Copyright (C) 2011 The Android Open Source Project
3238d9847d8f2ace658fb7337c8847a2088ddc9d1Dmitri Plotnikov *
4238d9847d8f2ace658fb7337c8847a2088ddc9d1Dmitri Plotnikov * Licensed under the Apache License, Version 2.0 (the "License");
5238d9847d8f2ace658fb7337c8847a2088ddc9d1Dmitri Plotnikov * you may not use this file except in compliance with the License.
6238d9847d8f2ace658fb7337c8847a2088ddc9d1Dmitri Plotnikov * You may obtain a copy of the License at
7238d9847d8f2ace658fb7337c8847a2088ddc9d1Dmitri Plotnikov *
8238d9847d8f2ace658fb7337c8847a2088ddc9d1Dmitri Plotnikov *      http://www.apache.org/licenses/LICENSE-2.0
9238d9847d8f2ace658fb7337c8847a2088ddc9d1Dmitri Plotnikov *
10238d9847d8f2ace658fb7337c8847a2088ddc9d1Dmitri Plotnikov * Unless required by applicable law or agreed to in writing, software
11238d9847d8f2ace658fb7337c8847a2088ddc9d1Dmitri Plotnikov * distributed under the License is distributed on an "AS IS" BASIS,
12238d9847d8f2ace658fb7337c8847a2088ddc9d1Dmitri Plotnikov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13238d9847d8f2ace658fb7337c8847a2088ddc9d1Dmitri Plotnikov * See the License for the specific language governing permissions and
14238d9847d8f2ace658fb7337c8847a2088ddc9d1Dmitri Plotnikov * limitations under the License.
15238d9847d8f2ace658fb7337c8847a2088ddc9d1Dmitri Plotnikov */
16238d9847d8f2ace658fb7337c8847a2088ddc9d1Dmitri Plotnikovpackage com.android.contacts.list;
17238d9847d8f2ace658fb7337c8847a2088ddc9d1Dmitri Plotnikov
1832f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaroimport android.app.Activity;
1932f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaroimport android.app.Fragment;
2032f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaroimport android.app.LoaderManager;
2132f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaroimport android.app.LoaderManager.LoaderCallbacks;
2232f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaroimport android.content.CursorLoader;
2332f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaroimport android.content.Loader;
24e5d06f534d58baa27fe6b1091b9724f81fd258c9Frank Sposaroimport android.content.res.Resources;
2532f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaroimport android.database.Cursor;
267a700cf798a19a8452b8671f643a05336f63f611Katherine Kuanimport android.graphics.Rect;
2732f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaroimport android.net.Uri;
2832f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaroimport android.os.Bundle;
29238d9847d8f2ace658fb7337c8847a2088ddc9d1Dmitri Plotnikovimport android.view.LayoutInflater;
30238d9847d8f2ace658fb7337c8847a2088ddc9d1Dmitri Plotnikovimport android.view.View;
31238d9847d8f2ace658fb7337c8847a2088ddc9d1Dmitri Plotnikovimport android.view.ViewGroup;
3232f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaroimport android.widget.ListView;
3337efa3aeea2e26fdee640b797efc39279500c4daFrank Sposaroimport android.widget.TextView;
34238d9847d8f2ace658fb7337c8847a2088ddc9d1Dmitri Plotnikov
3579a6b5d3a885bc508b4b98c92a946fe12643c444Chiao Chengimport com.android.contacts.common.ContactPhotoManager;
36c8dd78c595cfaf9766e59a2df012b16d6c05b213Chiao Chengimport com.android.contacts.common.ContactTileLoaderFactory;
37e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.R;
38e776d0366d5bf2f93a0cd0f14e48804e564bccf2Chiao Chengimport com.android.contacts.common.list.ContactTileAdapter;
39e776d0366d5bf2f93a0cd0f14e48804e564bccf2Chiao Chengimport com.android.contacts.common.list.ContactTileView;
40e776d0366d5bf2f93a0cd0f14e48804e564bccf2Chiao Chengimport com.android.contacts.common.list.ContactTileAdapter.DisplayType;
41e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Cheng
42238d9847d8f2ace658fb7337c8847a2088ddc9d1Dmitri Plotnikov/**
43238d9847d8f2ace658fb7337c8847a2088ddc9d1Dmitri Plotnikov * Fragment containing a list of starred contacts followed by a list of frequently contacted.
44f7689c377caba183daa41856d01a8c1a2f7ba811Katherine Kuan *
45f7689c377caba183daa41856d01a8c1a2f7ba811Katherine Kuan * TODO: Make this an abstract class so that the favorites, frequent, and group list functionality
46f7689c377caba183daa41856d01a8c1a2f7ba811Katherine Kuan * can be separated out. This will make it easier to customize any of those lists if necessary
47f7689c377caba183daa41856d01a8c1a2f7ba811Katherine Kuan * (i.e. adding header views to the ListViews in the fragment). This work was started
48f7689c377caba183daa41856d01a8c1a2f7ba811Katherine Kuan * by creating {@link ContactTileFrequentFragment}.
49238d9847d8f2ace658fb7337c8847a2088ddc9d1Dmitri Plotnikov */
507979ea27c046dfc2d9305b3282233046acef6ec4Frank Sposaropublic class ContactTileListFragment extends Fragment {
517979ea27c046dfc2d9305b3282233046acef6ec4Frank Sposaro    private static final String TAG = ContactTileListFragment.class.getSimpleName();
52b961b3b6dae6e3f1b6096631f130c38bfa33267cFrank Sposaro
5332f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaro    public interface Listener {
544e05a29c9b05c8cb74972aa5b9fe55fe35d7f45dJosh Gargus        void onContactSelected(Uri contactUri, Rect targetRect);
554e05a29c9b05c8cb74972aa5b9fe55fe35d7f45dJosh Gargus        void onCallNumberDirectly(String phoneNumber);
5632f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaro    }
577c5286ed8ba0d7fbe3683b560f69b3a2d4ff1e2aDmitri Plotnikov
5832f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaro    private Listener mListener;
59b961b3b6dae6e3f1b6096631f130c38bfa33267cFrank Sposaro    private ContactTileAdapter mAdapter;
6037efa3aeea2e26fdee640b797efc39279500c4daFrank Sposaro    private DisplayType mDisplayType;
6137efa3aeea2e26fdee640b797efc39279500c4daFrank Sposaro    private TextView mEmptyView;
6232f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaro    private ListView mListView;
635a03880a8e05de20f74d1621e5903a9c529397e3Dmitri Plotnikov
642fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu    private boolean mOptionsMenuHasFrequents;
652fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu
66469c6cc2226a9454bda86cd5aa95e771ab09fdb8Dmitri Plotnikov    @Override
6732f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaro    public void onAttach(Activity activity) {
6832f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaro        super.onAttach(activity);
69e5d06f534d58baa27fe6b1091b9724f81fd258c9Frank Sposaro
70e5d06f534d58baa27fe6b1091b9724f81fd258c9Frank Sposaro        Resources res = getResources();
712871d61514f014926d991e8b037828c67438e522Maurice Chu        int columnCount = res.getInteger(R.integer.contact_tile_column_count_in_favorites);
72e5d06f534d58baa27fe6b1091b9724f81fd258c9Frank Sposaro
73c569acf64701828c84271a81836dfd1a404dba03Frank Sposaro        mAdapter = new ContactTileAdapter(activity, mAdapterListener,
747979ea27c046dfc2d9305b3282233046acef6ec4Frank Sposaro                columnCount, mDisplayType);
755f34b2e20ad4a41b6dd3fd0703d59e085bffeb1cFrank Sposaro        mAdapter.setPhotoLoader(ContactPhotoManager.getInstance(activity));
765a03880a8e05de20f74d1621e5903a9c529397e3Dmitri Plotnikov    }
775a03880a8e05de20f74d1621e5903a9c529397e3Dmitri Plotnikov
7832f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaro    @Override
7932f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaro    public View onCreateView(LayoutInflater inflater, ViewGroup container,
8032f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaro            Bundle savedInstanceState) {
81f7689c377caba183daa41856d01a8c1a2f7ba811Katherine Kuan        return inflateAndSetupView(inflater, container, savedInstanceState,
82f7689c377caba183daa41856d01a8c1a2f7ba811Katherine Kuan                R.layout.contact_tile_list);
83f7689c377caba183daa41856d01a8c1a2f7ba811Katherine Kuan    }
84f7689c377caba183daa41856d01a8c1a2f7ba811Katherine Kuan
85f7689c377caba183daa41856d01a8c1a2f7ba811Katherine Kuan    protected View inflateAndSetupView(LayoutInflater inflater, ViewGroup container,
86f7689c377caba183daa41856d01a8c1a2f7ba811Katherine Kuan            Bundle savedInstanceState, int layoutResourceId) {
87f7689c377caba183daa41856d01a8c1a2f7ba811Katherine Kuan        View listLayout = inflater.inflate(layoutResourceId, container, false);
8837efa3aeea2e26fdee640b797efc39279500c4daFrank Sposaro
8937efa3aeea2e26fdee640b797efc39279500c4daFrank Sposaro        mEmptyView = (TextView) listLayout.findViewById(R.id.contact_tile_list_empty);
9037efa3aeea2e26fdee640b797efc39279500c4daFrank Sposaro        mListView = (ListView) listLayout.findViewById(R.id.contact_tile_list);
9137efa3aeea2e26fdee640b797efc39279500c4daFrank Sposaro
9232f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaro        mListView.setItemsCanFocus(true);
937979ea27c046dfc2d9305b3282233046acef6ec4Frank Sposaro        mListView.setAdapter(mAdapter);
9437efa3aeea2e26fdee640b797efc39279500c4daFrank Sposaro        return listLayout;
955a03880a8e05de20f74d1621e5903a9c529397e3Dmitri Plotnikov    }
965a03880a8e05de20f74d1621e5903a9c529397e3Dmitri Plotnikov
97238d9847d8f2ace658fb7337c8847a2088ddc9d1Dmitri Plotnikov    @Override
987979ea27c046dfc2d9305b3282233046acef6ec4Frank Sposaro    public void onStart() {
9932f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaro        super.onStart();
1002871d61514f014926d991e8b037828c67438e522Maurice Chu
1012871d61514f014926d991e8b037828c67438e522Maurice Chu        // initialize the loader for this display type and destroy all others
1022871d61514f014926d991e8b037828c67438e522Maurice Chu        final DisplayType[] loaderTypes = mDisplayType.values();
1032871d61514f014926d991e8b037828c67438e522Maurice Chu        for (int i = 0; i < loaderTypes.length; i++) {
1042871d61514f014926d991e8b037828c67438e522Maurice Chu            if (loaderTypes[i] == mDisplayType) {
1052871d61514f014926d991e8b037828c67438e522Maurice Chu                getLoaderManager().initLoader(mDisplayType.ordinal(), null,
1062871d61514f014926d991e8b037828c67438e522Maurice Chu                        mContactTileLoaderListener);
1072871d61514f014926d991e8b037828c67438e522Maurice Chu            } else {
1082871d61514f014926d991e8b037828c67438e522Maurice Chu                getLoaderManager().destroyLoader(loaderTypes[i].ordinal());
1092871d61514f014926d991e8b037828c67438e522Maurice Chu            }
1102871d61514f014926d991e8b037828c67438e522Maurice Chu        }
111238d9847d8f2ace658fb7337c8847a2088ddc9d1Dmitri Plotnikov    }
112238d9847d8f2ace658fb7337c8847a2088ddc9d1Dmitri Plotnikov
1132fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu    /**
1142fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu     * Returns whether there are any frequents with the side effect of setting the
1152fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu     * internal flag mOptionsMenuHasFrequents to the value.  This should be called externally
1162fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu     * by the activity that is about to prepare the options menu with the clear frequents
1172fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu     * menu item.
1182fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu     */
1192fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu    public boolean hasFrequents() {
1202fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu        mOptionsMenuHasFrequents = internalHasFrequents();
1212fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu        return mOptionsMenuHasFrequents;
1222fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu    }
1232fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu
1242fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu    /**
1252fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu     * Returns whether there are any frequents.
1262fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu     */
1272fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu    private boolean internalHasFrequents() {
1282fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu        return mAdapter.getNumFrequents() > 0;
1292fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu    }
1302fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu
131f00ff8b91e6c452839bb80c195bc8616797b9a0cFrank Sposaro    public void setColumnCount(int columnCount) {
132f00ff8b91e6c452839bb80c195bc8616797b9a0cFrank Sposaro        mAdapter.setColumnCount(columnCount);
133f00ff8b91e6c452839bb80c195bc8616797b9a0cFrank Sposaro    }
134f00ff8b91e6c452839bb80c195bc8616797b9a0cFrank Sposaro
135f00ff8b91e6c452839bb80c195bc8616797b9a0cFrank Sposaro    public void setDisplayType(DisplayType displayType) {
1367979ea27c046dfc2d9305b3282233046acef6ec4Frank Sposaro        mDisplayType = displayType;
1377979ea27c046dfc2d9305b3282233046acef6ec4Frank Sposaro        mAdapter.setDisplayType(mDisplayType);
138f00ff8b91e6c452839bb80c195bc8616797b9a0cFrank Sposaro    }
139f00ff8b91e6c452839bb80c195bc8616797b9a0cFrank Sposaro
1407979ea27c046dfc2d9305b3282233046acef6ec4Frank Sposaro    public void enableQuickContact(boolean enableQuickContact) {
1417979ea27c046dfc2d9305b3282233046acef6ec4Frank Sposaro        mAdapter.enableQuickContact(enableQuickContact);
1429e095d2ffc4a94d2fb925d19df6db12bc2b1e124Frank Sposaro    }
1439e095d2ffc4a94d2fb925d19df6db12bc2b1e124Frank Sposaro
1447979ea27c046dfc2d9305b3282233046acef6ec4Frank Sposaro    private final LoaderManager.LoaderCallbacks<Cursor> mContactTileLoaderListener =
14532f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaro            new LoaderCallbacks<Cursor>() {
1465a03880a8e05de20f74d1621e5903a9c529397e3Dmitri Plotnikov
14732f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaro        @Override
14832f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaro        public CursorLoader onCreateLoader(int id, Bundle args) {
1497979ea27c046dfc2d9305b3282233046acef6ec4Frank Sposaro            switch (mDisplayType) {
1507979ea27c046dfc2d9305b3282233046acef6ec4Frank Sposaro              case STARRED_ONLY:
1517979ea27c046dfc2d9305b3282233046acef6ec4Frank Sposaro                  return ContactTileLoaderFactory.createStarredLoader(getActivity());
1527979ea27c046dfc2d9305b3282233046acef6ec4Frank Sposaro              case STREQUENT:
1537979ea27c046dfc2d9305b3282233046acef6ec4Frank Sposaro                  return ContactTileLoaderFactory.createStrequentLoader(getActivity());
1540c07935a3d838ed24db7d20df839be97fe4c625aFrank Sposaro              case STREQUENT_PHONE_ONLY:
1550c07935a3d838ed24db7d20df839be97fe4c625aFrank Sposaro                  return ContactTileLoaderFactory.createStrequentPhoneOnlyLoader(getActivity());
1567979ea27c046dfc2d9305b3282233046acef6ec4Frank Sposaro              case FREQUENT_ONLY:
1577979ea27c046dfc2d9305b3282233046acef6ec4Frank Sposaro                  return ContactTileLoaderFactory.createFrequentLoader(getActivity());
1587979ea27c046dfc2d9305b3282233046acef6ec4Frank Sposaro              default:
1597979ea27c046dfc2d9305b3282233046acef6ec4Frank Sposaro                  throw new IllegalStateException(
1607979ea27c046dfc2d9305b3282233046acef6ec4Frank Sposaro                      "Unrecognized DisplayType " + mDisplayType);
1617979ea27c046dfc2d9305b3282233046acef6ec4Frank Sposaro            }
1625a03880a8e05de20f74d1621e5903a9c529397e3Dmitri Plotnikov        }
1635a03880a8e05de20f74d1621e5903a9c529397e3Dmitri Plotnikov
16432f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaro        @Override
16532f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaro        public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
1667979ea27c046dfc2d9305b3282233046acef6ec4Frank Sposaro            mAdapter.setContactCursor(data);
16737efa3aeea2e26fdee640b797efc39279500c4daFrank Sposaro            mEmptyView.setText(getEmptyStateText());
16837efa3aeea2e26fdee640b797efc39279500c4daFrank Sposaro            mListView.setEmptyView(mEmptyView);
1692fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu
1702fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu            // invalidate the menu options if needed
1712fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu            invalidateOptionsMenuIfNeeded();
17232f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaro        }
17368e32a3e3248a36f90e43e4f970ebe0196e74e43Dmitri Plotnikov
17432f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaro        @Override
1757979ea27c046dfc2d9305b3282233046acef6ec4Frank Sposaro        public void onLoaderReset(Loader<Cursor> loader) {}
17632f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaro    };
17732f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaro
1782fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu    private boolean isOptionsMenuChanged() {
1792fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu        return mOptionsMenuHasFrequents != internalHasFrequents();
1802fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu    }
1812fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu
1822fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu    private void invalidateOptionsMenuIfNeeded() {
1832fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu        if (isOptionsMenuChanged()) {
1842fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu            getActivity().invalidateOptionsMenu();
1852fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu        }
1862fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu    }
1872fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu
18837efa3aeea2e26fdee640b797efc39279500c4daFrank Sposaro    private String getEmptyStateText() {
18937efa3aeea2e26fdee640b797efc39279500c4daFrank Sposaro        String emptyText;
19037efa3aeea2e26fdee640b797efc39279500c4daFrank Sposaro        switch (mDisplayType) {
19137efa3aeea2e26fdee640b797efc39279500c4daFrank Sposaro            case STREQUENT:
19237efa3aeea2e26fdee640b797efc39279500c4daFrank Sposaro            case STREQUENT_PHONE_ONLY:
19337efa3aeea2e26fdee640b797efc39279500c4daFrank Sposaro            case STARRED_ONLY:
19437efa3aeea2e26fdee640b797efc39279500c4daFrank Sposaro                emptyText = getString(R.string.listTotalAllContactsZeroStarred);
19537efa3aeea2e26fdee640b797efc39279500c4daFrank Sposaro                break;
19637efa3aeea2e26fdee640b797efc39279500c4daFrank Sposaro            case FREQUENT_ONLY:
19737efa3aeea2e26fdee640b797efc39279500c4daFrank Sposaro            case GROUP_MEMBERS:
19837efa3aeea2e26fdee640b797efc39279500c4daFrank Sposaro                emptyText = getString(R.string.noContacts);
19937efa3aeea2e26fdee640b797efc39279500c4daFrank Sposaro                break;
20037efa3aeea2e26fdee640b797efc39279500c4daFrank Sposaro            default:
20137efa3aeea2e26fdee640b797efc39279500c4daFrank Sposaro                throw new IllegalArgumentException("Unrecognized DisplayType " + mDisplayType);
20237efa3aeea2e26fdee640b797efc39279500c4daFrank Sposaro        }
20337efa3aeea2e26fdee640b797efc39279500c4daFrank Sposaro        return emptyText;
20437efa3aeea2e26fdee640b797efc39279500c4daFrank Sposaro    }
20537efa3aeea2e26fdee640b797efc39279500c4daFrank Sposaro
2065f34b2e20ad4a41b6dd3fd0703d59e085bffeb1cFrank Sposaro    public void setListener(Listener listener) {
2075f34b2e20ad4a41b6dd3fd0703d59e085bffeb1cFrank Sposaro        mListener = listener;
2085f34b2e20ad4a41b6dd3fd0703d59e085bffeb1cFrank Sposaro    }
2095f34b2e20ad4a41b6dd3fd0703d59e085bffeb1cFrank Sposaro
2104e05a29c9b05c8cb74972aa5b9fe55fe35d7f45dJosh Gargus    private ContactTileView.Listener mAdapterListener =
2114e05a29c9b05c8cb74972aa5b9fe55fe35d7f45dJosh Gargus            new ContactTileView.Listener() {
21232f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaro        @Override
2137a700cf798a19a8452b8671f643a05336f63f611Katherine Kuan        public void onContactSelected(Uri contactUri, Rect targetRect) {
21432f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaro            if (mListener != null) {
2157a700cf798a19a8452b8671f643a05336f63f611Katherine Kuan                mListener.onContactSelected(contactUri, targetRect);
2167c5286ed8ba0d7fbe3683b560f69b3a2d4ff1e2aDmitri Plotnikov            }
2177c5286ed8ba0d7fbe3683b560f69b3a2d4ff1e2aDmitri Plotnikov        }
2184e05a29c9b05c8cb74972aa5b9fe55fe35d7f45dJosh Gargus
2194e05a29c9b05c8cb74972aa5b9fe55fe35d7f45dJosh Gargus        @Override
2204e05a29c9b05c8cb74972aa5b9fe55fe35d7f45dJosh Gargus        public void onCallNumberDirectly(String phoneNumber) {
2214e05a29c9b05c8cb74972aa5b9fe55fe35d7f45dJosh Gargus            if (mListener != null) {
2224e05a29c9b05c8cb74972aa5b9fe55fe35d7f45dJosh Gargus                mListener.onCallNumberDirectly(phoneNumber);
2234e05a29c9b05c8cb74972aa5b9fe55fe35d7f45dJosh Gargus            }
2244e05a29c9b05c8cb74972aa5b9fe55fe35d7f45dJosh Gargus        }
2252f77c85543e6c497e63cd0e216b70e58c1d13ec3Daniel Lehmann
2262f77c85543e6c497e63cd0e216b70e58c1d13ec3Daniel Lehmann        @Override
2272f77c85543e6c497e63cd0e216b70e58c1d13ec3Daniel Lehmann        public int getApproximateTileWidth() {
2282f77c85543e6c497e63cd0e216b70e58c1d13ec3Daniel Lehmann            return getView().getWidth() / mAdapter.getColumnCount();
2292f77c85543e6c497e63cd0e216b70e58c1d13ec3Daniel Lehmann        }
23032f395567c9d103e9101c2549f76945c9dee20b5Frank Sposaro    };
231238d9847d8f2ace658fb7337c8847a2088ddc9d1Dmitri Plotnikov}
232