PhoneFavoriteFragment.java revision b6553457d0c3e84eefa0a853090b680090a7b2f9
19b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa/*
29b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa * Copyright (C) 2011 The Android Open Source Project
39b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa *
49b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa * Licensed under the Apache License, Version 2.0 (the "License");
59b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa * you may not use this file except in compliance with the License.
69b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa * You may obtain a copy of the License at
79b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa *
89b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa *      http://www.apache.org/licenses/LICENSE-2.0
99b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa *
109b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa * Unless required by applicable law or agreed to in writing, software
119b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa * distributed under the License is distributed on an "AS IS" BASIS,
129b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa * See the License for the specific language governing permissions and
149b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa * limitations under the License.
159b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa */
169b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawapackage com.android.contacts.list;
179b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
189b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport com.android.contacts.ContactPhotoManager;
199b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport com.android.contacts.ContactTileLoaderFactory;
209b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport com.android.contacts.R;
217c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawaimport com.android.contacts.interactions.ImportExportDialogFragment;
229b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport com.android.contacts.preference.ContactsPreferences;
2334b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawaimport com.android.contacts.util.AccountFilterUtil;
249b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
259b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.app.Activity;
269b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.app.Fragment;
279b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.app.LoaderManager;
289b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.content.Context;
299b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.content.CursorLoader;
309b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.content.Intent;
319b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.content.Loader;
329b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.database.Cursor;
337a700cf798a19a8452b8671f643a05336f63f611Katherine Kuanimport android.graphics.Rect;
349b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.net.Uri;
359b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.os.Bundle;
367c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawaimport android.provider.ContactsContract;
379b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.provider.ContactsContract.Directory;
387c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawaimport android.provider.Settings;
399b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.util.Log;
409b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.view.LayoutInflater;
417c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawaimport android.view.Menu;
427c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawaimport android.view.MenuInflater;
437c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawaimport android.view.MenuItem;
449b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.view.View;
459b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.view.View.OnClickListener;
469b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.view.ViewGroup;
471dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawaimport android.widget.AbsListView;
489b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.widget.AdapterView;
499b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.widget.AdapterView.OnItemClickListener;
5034b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawaimport android.widget.FrameLayout;
519b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.widget.ListView;
529b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.widget.TextView;
539b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
549b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa/**
559b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa * Fragment for Phone UI's favorite screen.
569b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa *
579b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa * This fragment contains three kinds of contacts in one screen: "starred", "frequent", and "all"
589b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa * contacts. To show them at once, this merges results from {@link ContactTileAdapter} and
599b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa * {@link PhoneNumberListAdapter} into one unified list using {@link PhoneFavoriteMergedAdapter}.
609b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa * A contact filter header is also inserted between those adapters' results.
619b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa */
62091034c2d4c3ea69fc63c2e9d0956a109a13e08eDaisuke Miyakawapublic class PhoneFavoriteFragment extends Fragment implements OnItemClickListener {
639b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    private static final String TAG = PhoneFavoriteFragment.class.getSimpleName();
649b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    private static final boolean DEBUG = false;
659b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
669b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    /**
679b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa     * Used with LoaderManager.
689b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa     */
699b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    private static int LOADER_ID_CONTACT_TILE = 1;
709b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    private static int LOADER_ID_ALL_CONTACTS = 2;
719b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
729b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    private static final String KEY_FILTER = "filter";
739b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
7434b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa    private static final int REQUEST_CODE_ACCOUNT_FILTER = 1;
7534b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa
769b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    public interface Listener {
779b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        public void onContactSelected(Uri contactUri);
789b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    }
799b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
809b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    private class ContactTileLoaderListener implements LoaderManager.LoaderCallbacks<Cursor> {
819b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        @Override
829b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        public CursorLoader onCreateLoader(int id, Bundle args) {
839b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            if (DEBUG) Log.d(TAG, "ContactTileLoaderListener#onCreateLoader.");
849b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            return ContactTileLoaderFactory.createStrequentPhoneOnlyLoader(getActivity());
859b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        }
869b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
879b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        @Override
889b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
899b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            if (DEBUG) Log.d(TAG, "ContactTileLoaderListener#onLoadFinished");
909b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            mContactTileAdapter.setContactCursor(data);
919b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
929b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            if (mAllContactsForceReload) {
939b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa                mAllContactsAdapter.onDataReload();
949b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa                // Use restartLoader() to make LoaderManager to load the section again.
959b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa                getLoaderManager().restartLoader(
969b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa                        LOADER_ID_ALL_CONTACTS, null, mAllContactsLoaderListener);
979b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            } else if (!mAllContactsLoaderStarted) {
989b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa                // Load "all" contacts if not loaded yet.
999b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa                getLoaderManager().initLoader(
1009b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa                        LOADER_ID_ALL_CONTACTS, null, mAllContactsLoaderListener);
1019b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            }
1029b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            mAllContactsForceReload = false;
1039b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            mAllContactsLoaderStarted = true;
1049b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
1059b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            // Show the filter header with "loading" state.
1069b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            updateFilterHeaderView();
10734b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa            mAccountFilterHeader.setVisibility(View.VISIBLE);
1089b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        }
1099b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
1109b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        @Override
1119b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        public void onLoaderReset(Loader<Cursor> loader) {
1129b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            if (DEBUG) Log.d(TAG, "ContactTileLoaderListener#onLoaderReset. ");
1139b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        }
1149b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    }
1159b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
1169b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    private class AllContactsLoaderListener implements LoaderManager.LoaderCallbacks<Cursor> {
1179b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        @Override
1189b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        public Loader<Cursor> onCreateLoader(int id, Bundle args) {
1199b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            if (DEBUG) Log.d(TAG, "AllContactsLoaderListener#onCreateLoader");
1209b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            CursorLoader loader = new CursorLoader(getActivity(), null, null, null, null, null);
1219b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            mAllContactsAdapter.configureLoader(loader, Directory.DEFAULT);
1229b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            return loader;
1239b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        }
1249b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
1259b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        @Override
1269b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
1279b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            if (DEBUG) Log.d(TAG, "AllContactsLoaderListener#onLoadFinished");
1289b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            mAllContactsAdapter.changeCursor(0, data);
1299b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            updateFilterHeaderView();
1309b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            mAccountFilterHeaderContainer.setVisibility(View.VISIBLE);
1319b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        }
1329b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
1339b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        @Override
1349b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        public void onLoaderReset(Loader<Cursor> loader) {
1359b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            if (DEBUG) Log.d(TAG, "AllContactsLoaderListener#onLoaderReset. ");
1369b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        }
1379b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    }
1389b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
1399b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    private class ContactTileAdapterListener implements ContactTileAdapter.Listener {
1409b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        @Override
1417a700cf798a19a8452b8671f643a05336f63f611Katherine Kuan        public void onContactSelected(Uri contactUri, Rect targetRect) {
1429b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            if (mListener != null) {
1439b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa                mListener.onContactSelected(contactUri);
1449b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            }
1459b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        }
1469b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    }
1479b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
1489b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    private class FilterHeaderClickListener implements OnClickListener {
1499b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        @Override
1509b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        public void onClick(View view) {
15134b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa            AccountFilterUtil.startAccountFilterActivityForResult(
152b6553457d0c3e84eefa0a853090b680090a7b2f9Josh Gargus                    PhoneFavoriteFragment.this,
153b6553457d0c3e84eefa0a853090b680090a7b2f9Josh Gargus                    REQUEST_CODE_ACCOUNT_FILTER,
154b6553457d0c3e84eefa0a853090b680090a7b2f9Josh Gargus                    mFilter);
1559b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        }
1569b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    }
1579b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
1589b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    private class ContactsPreferenceChangeListener
1599b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            implements ContactsPreferences.ChangeListener {
1609b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        @Override
1619b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        public void onChange() {
1629b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            if (loadContactsPreferences()) {
1639b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa                requestReloadAllContacts();
1649b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            }
1659b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        }
1669b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    }
1679b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
1681dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa    private class ScrollListener implements ListView.OnScrollListener {
1691dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa        private boolean mShouldShowFastScroller;
1701dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa        @Override
1711dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa        public void onScroll(AbsListView view,
1721dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa                int firstVisibleItem, int visibleItemCount, int totalItemCount) {
1731dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa            // FastScroller should be visible only when the user is seeing "all" contacts section.
1741dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa            final boolean shouldShow = mAdapter.shouldShowFirstScroller(firstVisibleItem);
1751dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa            if (shouldShow != mShouldShowFastScroller) {
176532db253b803d98bfbbc457c5b559834cdb3b326Daisuke Miyakawa                mListView.setVerticalScrollBarEnabled(shouldShow);
1771dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa                mListView.setFastScrollEnabled(shouldShow);
1781dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa                mListView.setFastScrollAlwaysVisible(shouldShow);
1791dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa                mShouldShowFastScroller = shouldShow;
1801dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa            }
1811dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa        }
1821dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa
1831dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa        @Override
1841dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa        public void onScrollStateChanged(AbsListView view, int scrollState) {
1851dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa        }
1861dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa    }
1871dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa
1889b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    private Listener mListener;
1899b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    private PhoneFavoriteMergedAdapter mAdapter;
1909b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    private ContactTileAdapter mContactTileAdapter;
1919b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    private PhoneNumberListAdapter mAllContactsAdapter;
1929b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
1939b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    /**
1949b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa     * true when the loader for {@link PhoneNumberListAdapter} has started already.
1959b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa     */
1969b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    private boolean mAllContactsLoaderStarted;
1979b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    /**
1989b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa     * true when the loader for {@link PhoneNumberListAdapter} must reload "all" contacts again.
1999b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa     * It typically happens when {@link ContactsPreferences} has changed its settings
2009b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa     * (display order and sort order)
2019b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa     */
2029b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    private boolean mAllContactsForceReload;
2039b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
2049b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    private ContactsPreferences mContactsPrefs;
2059b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    private ContactListFilter mFilter;
2069b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
2079b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    private TextView mEmptyView;
2089b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    private ListView mListView;
20934b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa    /**
21034b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa     * Layout containing {@link #mAccountFilterHeader}. Used to limit area being "pressed".
21134b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa     */
21234b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa    private FrameLayout mAccountFilterHeaderContainer;
21334b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa    private View mAccountFilterHeader;
2149b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
2159b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    private final ContactTileAdapter.Listener mContactTileAdapterListener =
2169b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            new ContactTileAdapterListener();
2179b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    private final LoaderManager.LoaderCallbacks<Cursor> mContactTileLoaderListener =
2189b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            new ContactTileLoaderListener();
2199b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    private final LoaderManager.LoaderCallbacks<Cursor> mAllContactsLoaderListener =
2209b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            new AllContactsLoaderListener();
2219b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    private final OnClickListener mFilterHeaderClickListener = new FilterHeaderClickListener();
2229b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    private final ContactsPreferenceChangeListener mContactsPreferenceChangeListener =
2239b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            new ContactsPreferenceChangeListener();
2241dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa    private final ScrollListener mScrollListener = new ScrollListener();
2259b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
2269b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    @Override
2279b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    public void onCreate(Bundle savedState) {
2289b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        super.onCreate(savedState);
2299b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        if (savedState != null) {
2309b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            mFilter = savedState.getParcelable(KEY_FILTER);
2319b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        }
2327c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa        setHasOptionsMenu(true);
2339b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    }
2349b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
2359b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    @Override
2369b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    public void onSaveInstanceState(Bundle outState) {
2379b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        super.onSaveInstanceState(outState);
2389b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        outState.putParcelable(KEY_FILTER, mFilter);
2399b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    }
2409b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
2419b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    @Override
2429b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    public void onAttach(Activity activity) {
2439b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        super.onAttach(activity);
2449b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
2459b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        mContactsPrefs = new ContactsPreferences(activity);
2465db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa    }
2479b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
2485db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa    @Override
2495db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa    public View onCreateView(LayoutInflater inflater, ViewGroup container,
2505db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa            Bundle savedInstanceState) {
2515db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa        final View listLayout = inflater.inflate(R.layout.contact_tile_list, container, false);
2525db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa
2535db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa        mListView = (ListView) listLayout.findViewById(R.id.contact_tile_list);
2545db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa        mListView.setItemsCanFocus(true);
2555db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa        mListView.setOnItemClickListener(this);
256532db253b803d98bfbbc457c5b559834cdb3b326Daisuke Miyakawa        mListView.setVerticalScrollBarEnabled(false);
2575db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa        mListView.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_RIGHT);
2585db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa        mListView.setScrollBarStyle(ListView.SCROLLBARS_OUTSIDE_OVERLAY);
2599b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
2605db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa        initAdapters(getActivity(), inflater);
2615db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa
2625db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa        mListView.setAdapter(mAdapter);
2635db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa
2641dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa        mListView.setOnScrollListener(mScrollListener);
2651dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa        mListView.setFastScrollEnabled(false);
2661dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa        mListView.setFastScrollAlwaysVisible(false);
2671dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa
2685db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa        mEmptyView = (TextView) listLayout.findViewById(R.id.contact_tile_list_empty);
2695db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa        mEmptyView.setText(getString(R.string.listTotalAllContactsZero));
2705db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa        mListView.setEmptyView(mEmptyView);
2719b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
2729b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        updateFilterHeaderView();
2735db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa
2745db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa        return listLayout;
2759b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    }
2769b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
2779b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    /**
2789b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa     * Constructs and initializes {@link #mContactTileAdapter}, {@link #mAllContactsAdapter}, and
2799b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa     * {@link #mAllContactsAdapter}.
2805db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa     *
2815db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa     * TODO: Move all the code here to {@link PhoneFavoriteMergedAdapter} if possible.
2825db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa     * There are two problems: account header (whose content changes depending on filter settings)
2835db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa     * and OnClickListener (which initiates {@link Activity#startActivityForResult(Intent, int)}).
2845db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa     * See also issue 5429203, 5269692, and 5432286. If we are able to have a singleton for filter,
2855db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa     * this work will become easier.
2869b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa     */
2875db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa    private void initAdapters(Context context, LayoutInflater inflater) {
2889b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        mContactTileAdapter = new ContactTileAdapter(context, mContactTileAdapterListener,
2899b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa                getResources().getInteger(R.integer.contact_tile_column_count),
2909b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa                ContactTileAdapter.DisplayType.STREQUENT_PHONE_ONLY);
2919b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        mContactTileAdapter.setPhotoLoader(ContactPhotoManager.getInstance(context));
2929b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
2939b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        // Setup the "all" adapter manually. See also the setup logic in ContactEntryListFragment.
2949b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        mAllContactsAdapter = new PhoneNumberListAdapter(context);
2959b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        mAllContactsAdapter.setDisplayPhotos(true);
2969b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        mAllContactsAdapter.setQuickContactEnabled(true);
2979b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        mAllContactsAdapter.setSearchMode(false);
2989b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        mAllContactsAdapter.setIncludeProfile(false);
2999b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        mAllContactsAdapter.setSelectionVisible(false);
3009b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        mAllContactsAdapter.setDarkTheme(true);
3019b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        mAllContactsAdapter.setPhotoLoader(ContactPhotoManager.getInstance(context));
3029b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        // Disable directory header.
3039b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        mAllContactsAdapter.setHasHeader(0, false);
3049b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        // Show A-Z section index.
3059b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        mAllContactsAdapter.setSectionHeaderDisplayEnabled(true);
3069b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        // Disable pinned header. It doesn't work with this fragment.
3079b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        mAllContactsAdapter.setPinnedPartitionHeadersEnabled(false);
3089b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        // Put photos on left for consistency with "frequent" contacts section.
3099b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        mAllContactsAdapter.setPhotoPosition(ContactListItemView.PhotoPosition.LEFT);
3109b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
311e1c007eeb40a40b21e60bb4c8a42e0affd9fcdd1Daisuke Miyakawa        mAllContactsAdapter.setUseCallableUri(true);
312e1c007eeb40a40b21e60bb4c8a42e0affd9fcdd1Daisuke Miyakawa
3135db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa        if (mFilter != null) {
3145db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa            mAllContactsAdapter.setFilter(mFilter);
3155db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa        }
3165db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa
3175db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa        // Create the account filter header but keep it hidden until "all" contacts are loaded.
31834b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa        mAccountFilterHeaderContainer = new FrameLayout(context, null);
319b5c0b93e37e2b471ea46a1889e2eb194292284b7Daisuke Miyakawa        mAccountFilterHeader = inflater.inflate(R.layout.account_filter_header_for_phone_favorite,
320b5c0b93e37e2b471ea46a1889e2eb194292284b7Daisuke Miyakawa                mListView, false);
32134b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa        mAccountFilterHeader.setOnClickListener(mFilterHeaderClickListener);
32234b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa        mAccountFilterHeaderContainer.addView(mAccountFilterHeader);
3235db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa        mAccountFilterHeaderContainer.setVisibility(View.GONE);
3245db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa
3255db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa        mAdapter = new PhoneFavoriteMergedAdapter(context,
3265db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa                mContactTileAdapter, mAccountFilterHeaderContainer, mAllContactsAdapter);
3275db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa
3289b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    }
3299b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
3309b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    @Override
3317c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
3327c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa        super.onCreateOptionsMenu(menu, inflater);
333091034c2d4c3ea69fc63c2e9d0956a109a13e08eDaisuke Miyakawa        inflater.inflate(R.menu.phone_favorite_options, menu);
3347c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa    }
3357c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa
3367c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa    @Override
3377c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa    public boolean onOptionsItemSelected(MenuItem item) {
3387c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa        switch (item.getItemId()) {
3397c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa            case R.id.menu_import_export:
340e05f8efc11a383b8299e3a16b79a5d27531251d4Josh Gargus                // We hard-code the "contactsAreAvailable" argument because doing it properly would
341e05f8efc11a383b8299e3a16b79a5d27531251d4Josh Gargus                // involve querying a {@link ProviderStatusLoader}, which we don't want to do right
342091034c2d4c3ea69fc63c2e9d0956a109a13e08eDaisuke Miyakawa                // now in Dialtacts for (potential) performance reasons.  Compare with how it is
343e05f8efc11a383b8299e3a16b79a5d27531251d4Josh Gargus                // done in {@link PeopleActivity}.
344e05f8efc11a383b8299e3a16b79a5d27531251d4Josh Gargus                ImportExportDialogFragment.show(getFragmentManager(), true);
3457c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa                return true;
3467c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa            case R.id.menu_accounts:
3477c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa                final Intent intent = new Intent(Settings.ACTION_SYNC_SETTINGS);
3487c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa                intent.putExtra(Settings.EXTRA_AUTHORITIES, new String[] {
3497c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa                    ContactsContract.AUTHORITY
3507c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa                });
3517c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa                intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET);
3527c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa                startActivity(intent);
3537c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa                return true;
3547c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa        }
3557c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa        return false;
3567c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa    }
3577c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa
3587c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa    @Override
3599b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    public void onStart() {
3609b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        super.onStart();
3619b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
3629b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        mContactsPrefs.registerChangeListener(mContactsPreferenceChangeListener);
3639b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
3649b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        // If ContactsPreferences has changed, we need to reload "all" contacts with the new
3659b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        // settings. If mAllContactsFoarceReload is already true, it should be kept.
3669b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        if (loadContactsPreferences()) {
3679b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            mAllContactsForceReload = true;
3689b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        }
3699b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
3709b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        // Use initLoader() instead of reloadLoader() to refraing unnecessary reload.
3719b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        // This method call implicitly assures ContactTileLoaderListener's onLoadFinished() will
3729b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        // be called, on which we'll check if "all" contacts should be reloaded again or not.
3739b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        getLoaderManager().initLoader(LOADER_ID_CONTACT_TILE, null, mContactTileLoaderListener);
3749b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    }
3759b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
3769b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    @Override
3779b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    public void onStop() {
3789b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        super.onStop();
3799b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        mContactsPrefs.unregisterChangeListener();
3809b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    }
3819b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
3829b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    /**
3839b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa     * {@inheritDoc}
3849b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa     *
3859b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa     * This is only effective for elements provided by {@link #mContactTileAdapter}.
3869b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa     * {@link #mContactTileAdapter} has its own logic for click events.
3879b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa     */
3889b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    @Override
3899b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
3909b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        final int contactTileAdapterCount = mContactTileAdapter.getCount();
3919b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        if (position <= contactTileAdapterCount) {
3929b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            Log.e(TAG, "onItemClick() event for unexpected position. "
3939b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa                    + "The position " + position + " is before \"all\" section. Ignored.");
3949b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        } else {
3959b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            final int localPosition = position - mContactTileAdapter.getCount() - 1;
3969b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            if (mListener != null) {
3979b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa                mListener.onContactSelected(mAllContactsAdapter.getDataUri(localPosition));
3989b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            }
3999b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        }
4009b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    }
4019b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
40234b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa    @Override
40334b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa    public void onActivityResult(int requestCode, int resultCode, Intent data) {
40434b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa        if (requestCode == REQUEST_CODE_ACCOUNT_FILTER) {
40534b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa            if (getActivity() != null) {
40634b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa                AccountFilterUtil.handleAccountFilterResult(
40734b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa                        ContactListFilterController.getInstance(getActivity()), resultCode, data);
40834b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa            } else {
40934b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa                Log.e(TAG, "getActivity() returns null during Fragment#onActivityResult()");
41034b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa            }
41134b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa        }
41234b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa    }
41334b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa
4149b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    private boolean loadContactsPreferences() {
4159b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        if (mContactsPrefs == null || mAllContactsAdapter == null) {
4169b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            return false;
4179b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        }
4189b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
4199b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        boolean changed = false;
4209b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        if (mAllContactsAdapter.getContactNameDisplayOrder() != mContactsPrefs.getDisplayOrder()) {
4219b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            mAllContactsAdapter.setContactNameDisplayOrder(mContactsPrefs.getDisplayOrder());
4229b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            changed = true;
4239b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        }
4249b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
4259b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        if (mAllContactsAdapter.getSortOrder() != mContactsPrefs.getSortOrder()) {
4269b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            mAllContactsAdapter.setSortOrder(mContactsPrefs.getSortOrder());
4279b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            changed = true;
4289b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        }
4299b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
4309b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        return changed;
4319b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    }
4329b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
4339b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    /**
4349b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa     * Requests to reload "all" contacts. If the section is already loaded, this method will
4359b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa     * force reloading it now. If the section isn't loaded yet, the actual load may be done later
4369b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa     * (on {@link #onStart()}.
4379b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa     */
4389b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    private void requestReloadAllContacts() {
4399b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        if (DEBUG) {
4409b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            Log.d(TAG, "requestReloadAllContacts()"
4419b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa                    + " mAllContactsAdapter: " + mAllContactsAdapter
4429b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa                    + ", mAllContactsLoaderStarted: " + mAllContactsLoaderStarted);
4439b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        }
4449b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
4459b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        if (mAllContactsAdapter == null || !mAllContactsLoaderStarted) {
4469b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            // Remember this request until next load on onStart().
4479b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            mAllContactsForceReload = true;
4489b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            return;
4499b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        }
4509b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
4519b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        if (DEBUG) Log.d(TAG, "Reload \"all\" contacts now.");
4529b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
4539b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        mAllContactsAdapter.onDataReload();
4549b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        // Use restartLoader() to make LoaderManager to load the section again.
4559b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        getLoaderManager().restartLoader(LOADER_ID_ALL_CONTACTS, null, mAllContactsLoaderListener);
4569b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    }
4579b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
4589b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    private void updateFilterHeaderView() {
4599b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        final ContactListFilter filter = getFilter();
46034b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa        if (mAccountFilterHeader == null || mAllContactsAdapter == null || filter == null) {
46134b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa            return;
4629b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        }
46334b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa        AccountFilterUtil.updateAccountFilterTitleForPhone(
46434b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa                mAccountFilterHeader, filter, mAllContactsAdapter.isLoading(), true);
4659b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    }
4669b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
4679b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    public ContactListFilter getFilter() {
4689b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        return mFilter;
4699b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    }
4709b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
4719b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    public void setFilter(ContactListFilter filter) {
4729b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        if ((mFilter == null && filter == null) || (mFilter != null && mFilter.equals(filter))) {
4739b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            return;
4749b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        }
4759b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
4769b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        if (DEBUG) {
4779b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa            Log.d(TAG, "setFilter(). old filter (" + mFilter
4789b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa                    + ") will be replaced with new filter (" + filter + ")");
4799b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        }
4809b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
4819b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        mFilter = filter;
4829b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
4835db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa        if (mAllContactsAdapter != null) {
4845db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa            mAllContactsAdapter.setFilter(mFilter);
4855db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa            requestReloadAllContacts();
4865db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa            updateFilterHeaderView();
4875db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa        }
4889b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    }
4899b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa
4909b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    public void setListener(Listener listener) {
4919b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa        mListener = listener;
4929b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa    }
4939b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa}