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 android.app.Activity; 199b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.app.Fragment; 209b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.app.LoaderManager; 219b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.content.CursorLoader; 229b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.content.Intent; 239b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.content.Loader; 249b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.database.Cursor; 257a700cf798a19a8452b8671f643a05336f63f611Katherine Kuanimport android.graphics.Rect; 269b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.net.Uri; 279b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.os.Bundle; 2890f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawaimport android.os.Handler; 2990f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawaimport android.os.Message; 307c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawaimport android.provider.ContactsContract; 319b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.provider.ContactsContract.Directory; 327c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawaimport android.provider.Settings; 339b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.util.Log; 349b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.view.LayoutInflater; 357c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawaimport android.view.Menu; 367c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawaimport android.view.MenuInflater; 377c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawaimport android.view.MenuItem; 389b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.view.View; 399b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.view.View.OnClickListener; 409b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.view.ViewGroup; 411dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawaimport android.widget.AbsListView; 429b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.widget.AdapterView; 439b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.widget.AdapterView.OnItemClickListener; 4434b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawaimport android.widget.FrameLayout; 459b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.widget.ListView; 469b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawaimport android.widget.TextView; 479b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 48e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.ContactPhotoManager; 49e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.ContactTileLoaderFactory; 50e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.R; 51e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.dialog.ClearFrequentsDialog; 52e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.interactions.ImportExportDialogFragment; 53e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.preference.ContactsPreferences; 54e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Chengimport com.android.contacts.util.AccountFilterUtil; 55e0b2f1e2d01d1ac52ba207dc7ce76971d853298eChiao Cheng 569b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa/** 579b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa * Fragment for Phone UI's favorite screen. 589b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa * 599b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa * This fragment contains three kinds of contacts in one screen: "starred", "frequent", and "all" 609b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa * contacts. To show them at once, this merges results from {@link ContactTileAdapter} and 619b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa * {@link PhoneNumberListAdapter} into one unified list using {@link PhoneFavoriteMergedAdapter}. 629b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa * A contact filter header is also inserted between those adapters' results. 639b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa */ 64091034c2d4c3ea69fc63c2e9d0956a109a13e08eDaisuke Miyakawapublic class PhoneFavoriteFragment extends Fragment implements OnItemClickListener { 659b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa private static final String TAG = PhoneFavoriteFragment.class.getSimpleName(); 669b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa private static final boolean DEBUG = false; 679b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 689b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa /** 699b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa * Used with LoaderManager. 709b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa */ 719b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa private static int LOADER_ID_CONTACT_TILE = 1; 729b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa private static int LOADER_ID_ALL_CONTACTS = 2; 739b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 749b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa private static final String KEY_FILTER = "filter"; 759b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 7634b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa private static final int REQUEST_CODE_ACCOUNT_FILTER = 1; 7734b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa 789b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa public interface Listener { 799b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa public void onContactSelected(Uri contactUri); 804e05a29c9b05c8cb74972aa5b9fe55fe35d7f45dJosh Gargus public void onCallNumberDirectly(String phoneNumber); 819b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 829b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 839b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa private class ContactTileLoaderListener implements LoaderManager.LoaderCallbacks<Cursor> { 849b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa @Override 859b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa public CursorLoader onCreateLoader(int id, Bundle args) { 869b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa if (DEBUG) Log.d(TAG, "ContactTileLoaderListener#onCreateLoader."); 879b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa return ContactTileLoaderFactory.createStrequentPhoneOnlyLoader(getActivity()); 889b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 899b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 909b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa @Override 919b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 929b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa if (DEBUG) Log.d(TAG, "ContactTileLoaderListener#onLoadFinished"); 939b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa mContactTileAdapter.setContactCursor(data); 949b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 959b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa if (mAllContactsForceReload) { 969b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa mAllContactsAdapter.onDataReload(); 979b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa // Use restartLoader() to make LoaderManager to load the section again. 989b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa getLoaderManager().restartLoader( 999b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa LOADER_ID_ALL_CONTACTS, null, mAllContactsLoaderListener); 1009b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } else if (!mAllContactsLoaderStarted) { 1019b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa // Load "all" contacts if not loaded yet. 1029b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa getLoaderManager().initLoader( 1039b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa LOADER_ID_ALL_CONTACTS, null, mAllContactsLoaderListener); 1049b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 1059b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa mAllContactsForceReload = false; 1069b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa mAllContactsLoaderStarted = true; 1079b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 1089b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa // Show the filter header with "loading" state. 1099b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa updateFilterHeaderView(); 11034b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa mAccountFilterHeader.setVisibility(View.VISIBLE); 1112fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu 1122fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu // invalidate the options menu if needed 1132fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu invalidateOptionsMenuIfNeeded(); 1149b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 1159b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 1169b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa @Override 1179b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa public void onLoaderReset(Loader<Cursor> loader) { 1189b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa if (DEBUG) Log.d(TAG, "ContactTileLoaderListener#onLoaderReset. "); 1199b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 1209b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 1219b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 1229b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa private class AllContactsLoaderListener implements LoaderManager.LoaderCallbacks<Cursor> { 1239b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa @Override 1249b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa public Loader<Cursor> onCreateLoader(int id, Bundle args) { 1259b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa if (DEBUG) Log.d(TAG, "AllContactsLoaderListener#onCreateLoader"); 1269b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa CursorLoader loader = new CursorLoader(getActivity(), null, null, null, null, null); 1279b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa mAllContactsAdapter.configureLoader(loader, Directory.DEFAULT); 1289b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa return loader; 1299b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 1309b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 1319b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa @Override 1329b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 1339b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa if (DEBUG) Log.d(TAG, "AllContactsLoaderListener#onLoadFinished"); 1349b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa mAllContactsAdapter.changeCursor(0, data); 1359b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa updateFilterHeaderView(); 13690f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawa mHandler.removeMessages(MESSAGE_SHOW_LOADING_EFFECT); 13790f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawa mLoadingView.setVisibility(View.VISIBLE); 1389b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 1399b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 1409b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa @Override 1419b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa public void onLoaderReset(Loader<Cursor> loader) { 1429b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa if (DEBUG) Log.d(TAG, "AllContactsLoaderListener#onLoaderReset. "); 1439b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 1449b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 1459b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 1464e05a29c9b05c8cb74972aa5b9fe55fe35d7f45dJosh Gargus private class ContactTileAdapterListener implements ContactTileView.Listener { 1479b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa @Override 1487a700cf798a19a8452b8671f643a05336f63f611Katherine Kuan public void onContactSelected(Uri contactUri, Rect targetRect) { 1499b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa if (mListener != null) { 1509b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa mListener.onContactSelected(contactUri); 1519b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 1529b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 1534e05a29c9b05c8cb74972aa5b9fe55fe35d7f45dJosh Gargus 1544e05a29c9b05c8cb74972aa5b9fe55fe35d7f45dJosh Gargus @Override 1554e05a29c9b05c8cb74972aa5b9fe55fe35d7f45dJosh Gargus public void onCallNumberDirectly(String phoneNumber) { 1564e05a29c9b05c8cb74972aa5b9fe55fe35d7f45dJosh Gargus if (mListener != null) { 1574e05a29c9b05c8cb74972aa5b9fe55fe35d7f45dJosh Gargus mListener.onCallNumberDirectly(phoneNumber); 1584e05a29c9b05c8cb74972aa5b9fe55fe35d7f45dJosh Gargus } 1594e05a29c9b05c8cb74972aa5b9fe55fe35d7f45dJosh Gargus } 1602f77c85543e6c497e63cd0e216b70e58c1d13ec3Daniel Lehmann 1612f77c85543e6c497e63cd0e216b70e58c1d13ec3Daniel Lehmann @Override 1622f77c85543e6c497e63cd0e216b70e58c1d13ec3Daniel Lehmann public int getApproximateTileWidth() { 1632f77c85543e6c497e63cd0e216b70e58c1d13ec3Daniel Lehmann return getView().getWidth() / mContactTileAdapter.getColumnCount(); 1642f77c85543e6c497e63cd0e216b70e58c1d13ec3Daniel Lehmann } 1659b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 1669b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 1679b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa private class FilterHeaderClickListener implements OnClickListener { 1689b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa @Override 1699b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa public void onClick(View view) { 17034b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa AccountFilterUtil.startAccountFilterActivityForResult( 171b6553457d0c3e84eefa0a853090b680090a7b2f9Josh Gargus PhoneFavoriteFragment.this, 172b6553457d0c3e84eefa0a853090b680090a7b2f9Josh Gargus REQUEST_CODE_ACCOUNT_FILTER, 173b6553457d0c3e84eefa0a853090b680090a7b2f9Josh Gargus mFilter); 1749b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 1759b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 1769b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 1779b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa private class ContactsPreferenceChangeListener 1789b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa implements ContactsPreferences.ChangeListener { 1799b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa @Override 1809b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa public void onChange() { 1819b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa if (loadContactsPreferences()) { 1829b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa requestReloadAllContacts(); 1839b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 1849b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 1859b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 1869b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 1871dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa private class ScrollListener implements ListView.OnScrollListener { 1881dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa private boolean mShouldShowFastScroller; 1891dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa @Override 1901dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa public void onScroll(AbsListView view, 1911dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa int firstVisibleItem, int visibleItemCount, int totalItemCount) { 1921dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa // FastScroller should be visible only when the user is seeing "all" contacts section. 1931dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa final boolean shouldShow = mAdapter.shouldShowFirstScroller(firstVisibleItem); 1941dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa if (shouldShow != mShouldShowFastScroller) { 195532db253b803d98bfbbc457c5b559834cdb3b326Daisuke Miyakawa mListView.setVerticalScrollBarEnabled(shouldShow); 1961dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa mListView.setFastScrollEnabled(shouldShow); 1971dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa mListView.setFastScrollAlwaysVisible(shouldShow); 1981dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa mShouldShowFastScroller = shouldShow; 1991dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa } 2001dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa } 2011dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa 2021dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa @Override 2031dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa public void onScrollStateChanged(AbsListView view, int scrollState) { 2041dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa } 2051dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa } 2061dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa 20790f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawa private static final int MESSAGE_SHOW_LOADING_EFFECT = 1; 20890f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawa private static final int LOADING_EFFECT_DELAY = 500; // ms 20990f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawa private final Handler mHandler = new Handler() { 21090f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawa @Override 21190f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawa public void handleMessage(Message msg) { 21290f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawa switch (msg.what) { 21390f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawa case MESSAGE_SHOW_LOADING_EFFECT: 21490f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawa mLoadingView.setVisibility(View.VISIBLE); 21590f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawa break; 21690f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawa } 21790f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawa } 21890f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawa }; 21990f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawa 2209b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa private Listener mListener; 2219b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa private PhoneFavoriteMergedAdapter mAdapter; 2229b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa private ContactTileAdapter mContactTileAdapter; 2239b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa private PhoneNumberListAdapter mAllContactsAdapter; 2249b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 2259b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa /** 2269b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa * true when the loader for {@link PhoneNumberListAdapter} has started already. 2279b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa */ 2289b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa private boolean mAllContactsLoaderStarted; 2299b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa /** 2309b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa * true when the loader for {@link PhoneNumberListAdapter} must reload "all" contacts again. 2319b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa * It typically happens when {@link ContactsPreferences} has changed its settings 2329b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa * (display order and sort order) 2339b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa */ 2349b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa private boolean mAllContactsForceReload; 2359b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 2369b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa private ContactsPreferences mContactsPrefs; 2379b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa private ContactListFilter mFilter; 2389b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 2399b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa private TextView mEmptyView; 2409b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa private ListView mListView; 24134b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa /** 24234b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa * Layout containing {@link #mAccountFilterHeader}. Used to limit area being "pressed". 24334b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa */ 24434b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa private FrameLayout mAccountFilterHeaderContainer; 24534b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa private View mAccountFilterHeader; 2469b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 24790f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawa /** 24890f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawa * Layout used when contacts load is slower than expected and thus "loading" view should be 24990f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawa * shown. 25090f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawa */ 25190f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawa private View mLoadingView; 25290f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawa 2534e05a29c9b05c8cb74972aa5b9fe55fe35d7f45dJosh Gargus private final ContactTileView.Listener mContactTileAdapterListener = 2549b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa new ContactTileAdapterListener(); 2559b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa private final LoaderManager.LoaderCallbacks<Cursor> mContactTileLoaderListener = 2569b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa new ContactTileLoaderListener(); 2579b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa private final LoaderManager.LoaderCallbacks<Cursor> mAllContactsLoaderListener = 2589b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa new AllContactsLoaderListener(); 2599b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa private final OnClickListener mFilterHeaderClickListener = new FilterHeaderClickListener(); 2609b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa private final ContactsPreferenceChangeListener mContactsPreferenceChangeListener = 2619b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa new ContactsPreferenceChangeListener(); 2621dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa private final ScrollListener mScrollListener = new ScrollListener(); 2639b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 2642fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu private boolean mOptionsMenuHasFrequents; 2652fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu 2669b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa @Override 2670da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa public void onAttach(Activity activity) { 2680da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa if (DEBUG) Log.d(TAG, "onAttach()"); 2690da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa super.onAttach(activity); 2700da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa 2710da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa mContactsPrefs = new ContactsPreferences(activity); 2720da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa 2730da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa // Construct two base adapters which will become part of PhoneFavoriteMergedAdapter. 2740da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa // We don't construct the resultant adapter at this moment since it requires LayoutInflater 2750da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa // that will be available on onCreateView(). 2760da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa 2770da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa mContactTileAdapter = new ContactTileAdapter(activity, mContactTileAdapterListener, 2782871d61514f014926d991e8b037828c67438e522Maurice Chu getResources().getInteger(R.integer.contact_tile_column_count_in_favorites), 2790da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa ContactTileAdapter.DisplayType.STREQUENT_PHONE_ONLY); 2800da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa mContactTileAdapter.setPhotoLoader(ContactPhotoManager.getInstance(activity)); 2810da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa 2820da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa // Setup the "all" adapter manually. See also the setup logic in ContactEntryListFragment. 2830da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa mAllContactsAdapter = new PhoneNumberListAdapter(activity); 2840da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa mAllContactsAdapter.setDisplayPhotos(true); 2850da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa mAllContactsAdapter.setQuickContactEnabled(true); 2860da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa mAllContactsAdapter.setSearchMode(false); 2870da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa mAllContactsAdapter.setIncludeProfile(false); 2880da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa mAllContactsAdapter.setSelectionVisible(false); 2890da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa mAllContactsAdapter.setDarkTheme(true); 2900da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa mAllContactsAdapter.setPhotoLoader(ContactPhotoManager.getInstance(activity)); 2910da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa // Disable directory header. 2920da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa mAllContactsAdapter.setHasHeader(0, false); 2930da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa // Show A-Z section index. 2940da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa mAllContactsAdapter.setSectionHeaderDisplayEnabled(true); 2950da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa // Disable pinned header. It doesn't work with this fragment. 2960da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa mAllContactsAdapter.setPinnedPartitionHeadersEnabled(false); 2970da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa // Put photos on left for consistency with "frequent" contacts section. 2980da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa mAllContactsAdapter.setPhotoPosition(ContactListItemView.PhotoPosition.LEFT); 2990da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa 3000da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa // Use Callable.CONTENT_URI which will include not only phone numbers but also SIP 3010da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa // addresses. 3020da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa mAllContactsAdapter.setUseCallableUri(true); 3030da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa 3040da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa mAllContactsAdapter.setContactNameDisplayOrder(mContactsPrefs.getDisplayOrder()); 3050da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa mAllContactsAdapter.setSortOrder(mContactsPrefs.getSortOrder()); 3060da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa } 3070da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa 3080da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa @Override 3099b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa public void onCreate(Bundle savedState) { 3100da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa if (DEBUG) Log.d(TAG, "onCreate()"); 3119b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa super.onCreate(savedState); 3129b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa if (savedState != null) { 3139b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa mFilter = savedState.getParcelable(KEY_FILTER); 3140da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa 3150da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa if (mFilter != null) { 3160da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa mAllContactsAdapter.setFilter(mFilter); 3170da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa } 3189b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 3197c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa setHasOptionsMenu(true); 3209b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 3219b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 3229b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa @Override 3239b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa public void onSaveInstanceState(Bundle outState) { 3249b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa super.onSaveInstanceState(outState); 3259b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa outState.putParcelable(KEY_FILTER, mFilter); 3269b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 3279b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 3289b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa @Override 3295db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa public View onCreateView(LayoutInflater inflater, ViewGroup container, 3305db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa Bundle savedInstanceState) { 331902170690532fceb9a3e13ad00f6aff00f95b10fDaisuke Miyakawa final View listLayout = inflater.inflate( 332902170690532fceb9a3e13ad00f6aff00f95b10fDaisuke Miyakawa R.layout.phone_contact_tile_list, container, false); 3335db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa 3345db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa mListView = (ListView) listLayout.findViewById(R.id.contact_tile_list); 3355db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa mListView.setItemsCanFocus(true); 3365db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa mListView.setOnItemClickListener(this); 337532db253b803d98bfbbc457c5b559834cdb3b326Daisuke Miyakawa mListView.setVerticalScrollBarEnabled(false); 3385db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa mListView.setVerticalScrollbarPosition(View.SCROLLBAR_POSITION_RIGHT); 3395db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa mListView.setScrollBarStyle(ListView.SCROLLBARS_OUTSIDE_OVERLAY); 3409b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 3410da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa // Create the account filter header but keep it hidden until "all" contacts are loaded. 3420da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa mAccountFilterHeaderContainer = new FrameLayout(getActivity(), null); 3430da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa mAccountFilterHeader = inflater.inflate(R.layout.account_filter_header_for_phone_favorite, 3440da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa mListView, false); 3450da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa mAccountFilterHeader.setOnClickListener(mFilterHeaderClickListener); 3460da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa mAccountFilterHeaderContainer.addView(mAccountFilterHeader); 34790f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawa 34890f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawa mLoadingView = inflater.inflate(R.layout.phone_loading_contacts, mListView, false); 3490da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa 3500da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa mAdapter = new PhoneFavoriteMergedAdapter(getActivity(), 35190f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawa mContactTileAdapter, mAccountFilterHeaderContainer, mAllContactsAdapter, 35290f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawa mLoadingView); 3535db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa 3545db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa mListView.setAdapter(mAdapter); 3555db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa 3561dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa mListView.setOnScrollListener(mScrollListener); 3571dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa mListView.setFastScrollEnabled(false); 3581dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa mListView.setFastScrollAlwaysVisible(false); 3591dff6b60c28fa34e477b84c95c4bbe6c9b482416Daisuke Miyakawa 3605db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa mEmptyView = (TextView) listLayout.findViewById(R.id.contact_tile_list_empty); 3615db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa mEmptyView.setText(getString(R.string.listTotalAllContactsZero)); 3625db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa mListView.setEmptyView(mEmptyView); 3639b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 3649b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa updateFilterHeaderView(); 3655db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa 3665db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa return listLayout; 3679b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 3689b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 3692fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu private boolean isOptionsMenuChanged() { 3702fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu return mOptionsMenuHasFrequents != hasFrequents(); 3712fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu } 3722fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu 3732fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu private void invalidateOptionsMenuIfNeeded() { 3742fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu if (isOptionsMenuChanged()) { 3752fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu getActivity().invalidateOptionsMenu(); 3762fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu } 3772fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu } 3782fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu 3799b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa @Override 3807c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 3817c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa super.onCreateOptionsMenu(menu, inflater); 382091034c2d4c3ea69fc63c2e9d0956a109a13e08eDaisuke Miyakawa inflater.inflate(R.menu.phone_favorite_options, menu); 3837c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa } 3847c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa 3857c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa @Override 3862fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu public void onPrepareOptionsMenu(Menu menu) { 3872fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu final MenuItem clearFrequents = menu.findItem(R.id.menu_clear_frequents); 3882fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu mOptionsMenuHasFrequents = hasFrequents(); 3892fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu clearFrequents.setVisible(mOptionsMenuHasFrequents); 3902fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu } 3912fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu 3922fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu private boolean hasFrequents() { 3932fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu return mContactTileAdapter.getNumFrequents() > 0; 3942fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu } 3952fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu 3962fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu @Override 3977c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa public boolean onOptionsItemSelected(MenuItem item) { 3987c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa switch (item.getItemId()) { 3997c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa case R.id.menu_import_export: 400e05f8efc11a383b8299e3a16b79a5d27531251d4Josh Gargus // We hard-code the "contactsAreAvailable" argument because doing it properly would 401e05f8efc11a383b8299e3a16b79a5d27531251d4Josh Gargus // involve querying a {@link ProviderStatusLoader}, which we don't want to do right 402091034c2d4c3ea69fc63c2e9d0956a109a13e08eDaisuke Miyakawa // now in Dialtacts for (potential) performance reasons. Compare with how it is 403e05f8efc11a383b8299e3a16b79a5d27531251d4Josh Gargus // done in {@link PeopleActivity}. 404e05f8efc11a383b8299e3a16b79a5d27531251d4Josh Gargus ImportExportDialogFragment.show(getFragmentManager(), true); 4057c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa return true; 4067c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa case R.id.menu_accounts: 4077c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa final Intent intent = new Intent(Settings.ACTION_SYNC_SETTINGS); 4087c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa intent.putExtra(Settings.EXTRA_AUTHORITIES, new String[] { 4097c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa ContactsContract.AUTHORITY 4107c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa }); 4117c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET); 4127c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa startActivity(intent); 4137c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa return true; 4142fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu case R.id.menu_clear_frequents: 4152fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu ClearFrequentsDialog.show(getFragmentManager()); 4162fc4de31fe2d6a261d3eeaff69ea944a5383003eMaurice Chu return true; 4177c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa } 4187c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa return false; 4197c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa } 4207c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa 4217c30236364c71618da4b266a61a77e9711aa23f1Daisuke Miyakawa @Override 4229b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa public void onStart() { 4239b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa super.onStart(); 4249b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 4259b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa mContactsPrefs.registerChangeListener(mContactsPreferenceChangeListener); 4269b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 4279b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa // If ContactsPreferences has changed, we need to reload "all" contacts with the new 4289b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa // settings. If mAllContactsFoarceReload is already true, it should be kept. 4299b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa if (loadContactsPreferences()) { 4309b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa mAllContactsForceReload = true; 4319b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 4329b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 4330da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa // Use initLoader() instead of restartLoader() to refraining unnecessary reload. 4349b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa // This method call implicitly assures ContactTileLoaderListener's onLoadFinished() will 4359b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa // be called, on which we'll check if "all" contacts should be reloaded again or not. 4369b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa getLoaderManager().initLoader(LOADER_ID_CONTACT_TILE, null, mContactTileLoaderListener); 43790f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawa 43890f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawa // Delay showing "loading" view until certain amount of time so that users won't see 43990f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawa // instant flash of the view when the contacts load is fast enough. 44090f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawa // This will be kept shown until both tile and all sections are loaded. 44190f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawa mLoadingView.setVisibility(View.INVISIBLE); 44290f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawa mHandler.sendEmptyMessageDelayed(MESSAGE_SHOW_LOADING_EFFECT, LOADING_EFFECT_DELAY); 4439b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 4449b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 4459b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa @Override 4469b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa public void onStop() { 4479b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa super.onStop(); 4489b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa mContactsPrefs.unregisterChangeListener(); 4499b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 4509b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 4519b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa /** 4529b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa * {@inheritDoc} 4539b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa * 4549b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa * This is only effective for elements provided by {@link #mContactTileAdapter}. 4559b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa * {@link #mContactTileAdapter} has its own logic for click events. 4569b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa */ 4579b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa @Override 4589b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 4599b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa final int contactTileAdapterCount = mContactTileAdapter.getCount(); 4609b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa if (position <= contactTileAdapterCount) { 4619b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa Log.e(TAG, "onItemClick() event for unexpected position. " 4629b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa + "The position " + position + " is before \"all\" section. Ignored."); 4639b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } else { 4649b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa final int localPosition = position - mContactTileAdapter.getCount() - 1; 4659b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa if (mListener != null) { 4669b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa mListener.onContactSelected(mAllContactsAdapter.getDataUri(localPosition)); 4679b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 4689b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 4699b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 4709b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 47134b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa @Override 47234b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa public void onActivityResult(int requestCode, int resultCode, Intent data) { 47334b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa if (requestCode == REQUEST_CODE_ACCOUNT_FILTER) { 47434b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa if (getActivity() != null) { 47534b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa AccountFilterUtil.handleAccountFilterResult( 47634b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa ContactListFilterController.getInstance(getActivity()), resultCode, data); 47734b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa } else { 47834b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa Log.e(TAG, "getActivity() returns null during Fragment#onActivityResult()"); 47934b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa } 48034b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa } 48134b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa } 48234b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa 4839b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa private boolean loadContactsPreferences() { 4849b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa if (mContactsPrefs == null || mAllContactsAdapter == null) { 4859b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa return false; 4869b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 4879b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 4889b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa boolean changed = false; 4890da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa final int currentDisplayOrder = mContactsPrefs.getDisplayOrder(); 4900da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa if (mAllContactsAdapter.getContactNameDisplayOrder() != currentDisplayOrder) { 4910da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa mAllContactsAdapter.setContactNameDisplayOrder(currentDisplayOrder); 4929b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa changed = true; 4939b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 4949b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 4950da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa final int currentSortOrder = mContactsPrefs.getSortOrder(); 4960da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa if (mAllContactsAdapter.getSortOrder() != currentSortOrder) { 4970da88d6359b1b8c7f4998d7f58a467ad65d40f84Daisuke Miyakawa mAllContactsAdapter.setSortOrder(currentSortOrder); 4989b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa changed = true; 4999b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 5009b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 5019b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa return changed; 5029b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 5039b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 5049b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa /** 5059b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa * Requests to reload "all" contacts. If the section is already loaded, this method will 5069b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa * force reloading it now. If the section isn't loaded yet, the actual load may be done later 5079b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa * (on {@link #onStart()}. 5089b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa */ 5099b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa private void requestReloadAllContacts() { 5109b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa if (DEBUG) { 5119b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa Log.d(TAG, "requestReloadAllContacts()" 5129b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa + " mAllContactsAdapter: " + mAllContactsAdapter 5139b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa + ", mAllContactsLoaderStarted: " + mAllContactsLoaderStarted); 5149b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 5159b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 5169b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa if (mAllContactsAdapter == null || !mAllContactsLoaderStarted) { 5179b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa // Remember this request until next load on onStart(). 5189b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa mAllContactsForceReload = true; 5199b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa return; 5209b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 5219b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 5229b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa if (DEBUG) Log.d(TAG, "Reload \"all\" contacts now."); 5239b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 5249b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa mAllContactsAdapter.onDataReload(); 5259b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa // Use restartLoader() to make LoaderManager to load the section again. 5269b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa getLoaderManager().restartLoader(LOADER_ID_ALL_CONTACTS, null, mAllContactsLoaderListener); 5279b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 5289b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 5299b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa private void updateFilterHeaderView() { 5309b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa final ContactListFilter filter = getFilter(); 53134b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa if (mAccountFilterHeader == null || mAllContactsAdapter == null || filter == null) { 53234b901ca7781cf7fdd4f6275ef98ae73c95749c2Daisuke Miyakawa return; 5339b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 53490f40d0162e4cee5b94bf3203c059e27f6472fabDaisuke Miyakawa AccountFilterUtil.updateAccountFilterTitleForPhone(mAccountFilterHeader, filter, true); 5359b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 5369b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 5379b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa public ContactListFilter getFilter() { 5389b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa return mFilter; 5399b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 5409b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 5419b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa public void setFilter(ContactListFilter filter) { 5429b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa if ((mFilter == null && filter == null) || (mFilter != null && mFilter.equals(filter))) { 5439b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa return; 5449b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 5459b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 5469b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa if (DEBUG) { 5479b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa Log.d(TAG, "setFilter(). old filter (" + mFilter 5489b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa + ") will be replaced with new filter (" + filter + ")"); 5499b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 5509b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 5519b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa mFilter = filter; 5529b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 5535db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa if (mAllContactsAdapter != null) { 5545db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa mAllContactsAdapter.setFilter(mFilter); 5555db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa requestReloadAllContacts(); 5565db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa updateFilterHeaderView(); 5575db4f136163675105813900b1f3f7da48bde97b6Daisuke Miyakawa } 5589b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 5599b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa 5609b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa public void setListener(Listener listener) { 5619b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa mListener = listener; 5629b9104874ec0680ac60cb0527d127fc1c34bdb7eDaisuke Miyakawa } 563aabc1e81c2d43827fe2ad0bdde6851bdfb431924Josh Gargus} 564