Java tutorial
/* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.visva.voicerecorder.view.fragments; import java.util.ArrayList; import java.util.Locale; import android.app.Activity; import android.app.SearchManager; import android.content.Context; import android.content.Intent; import android.content.res.Resources; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.provider.ContactsContract.Contacts; import android.support.v4.app.LoaderManager; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.support.v4.widget.CursorAdapter; import android.text.SpannableString; import android.text.TextUtils; import android.text.style.TextAppearanceSpan; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AlphabetIndexer; import android.widget.Button; import android.widget.ImageView; import android.widget.ListView; import android.widget.PopupWindow.OnDismissListener; import android.widget.SectionIndexer; import android.widget.TextView; import android.widget.Toast; import com.gc.materialdesign.widgets.Dialog; import com.visva.voicerecorder.MyCallRecorderApplication; import com.visva.voicerecorder.R; import com.visva.voicerecorder.constant.MyCallRecorderConstant; import com.visva.voicerecorder.log.AIOLog; import com.visva.voicerecorder.model.FavouriteItem; import com.visva.voicerecorder.utils.ContactsQuery; import com.visva.voicerecorder.utils.StringUtility; import com.visva.voicerecorder.utils.Utils; import com.visva.voicerecorder.view.activity.ActivityHome; import com.visva.voicerecorder.view.common.FragmentBasic; import com.visva.voicerecorder.view.widget.CircleImageView; import com.visva.voicerecorder.view.widget.quickaction.ActionItem; import com.visva.voicerecorder.view.widget.quickaction.QuickAction; /** * This fragment displays a list of contacts stored in the Contacts Provider. Each item in the list * shows the contact's thumbnail photo and display name. On devices with large screens, this * fragment's UI appears as part of a two-pane layout, along with the UI of * {@link FragmentContactDetail}. On smaller screens, this fragment's UI appears as a single pane. * * This Fragment retrieves contacts based on a search string. If the user doesn't enter a search * string, then the list contains all the contacts in the Contacts Provider. If the user enters a * search string, then the list contains only those contacts whose data matches the string. The * Contacts Provider itself controls the matching algorithm, which is a "substring" search: if the * search string is a substring of any of the contacts data, then there is a match. * * On newer API platforms, the search is implemented in a SearchView in the ActionBar; as the user * types the search string, the list automatically refreshes to display results ("type to filter"). * On older platforms, the user must enter the full string and trigger the search. In response, the * trigger starts a new Activity which loads a fresh instance of this fragment. The resulting UI * displays the filtered list and disables the search feature to prevent furthering searching. */ public class FragmentContact extends FragmentBasic implements AdapterView.OnItemClickListener, LoaderManager.LoaderCallbacks<Cursor>, AdapterView.OnItemLongClickListener { // ======================Constant Define===================== // Bundle key for saving previously selected search result item private static final String STATE_PREVIOUSLY_SELECTED_KEY = "com.example.android.contactslist.ui.SELECTED_ITEM"; // ======================Control Define ===================== private ListView mListContact; private TextView mTextNoContact; private QuickAction mQuickAction; // =======================Class Define ====================== // ======================Variable Define===================== private ContactsAdapter mAdapter; // The main query adapter private String mSearchTerm; // Stores the current search query term // Contact selected listener that allows the activity holding this fragment to be notified of // a contact being selected private OnContactsInteractionListener mOnContactSelectedListener; // Stores the previously selected search item so that on a configuration change the same item // can be reselected again private int mPreviouslySelectedSearchItem = 0; // Whether or not the search query has changed since the last time the loader was refreshed private boolean mSearchQueryChanged; // Whether or not this fragment is showing in a two-pane layout private boolean mIsTwoPaneLayout; private boolean mIsOnItemLongClick; private int mSelectedPosition; /** * Fragments require an empty constructor. */ public FragmentContact() { } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Check if this fragment is part of a two-pane set up or a single pane by reading a // boolean from the application resource directories. This lets allows us to easily specify // which screen sizes should use a two-pane layout by setting this boolean in the // corresponding resource size-qualified directory. mIsTwoPaneLayout = getResources().getBoolean(R.bool.has_two_panes); // Let this fragment contribute menu items setHasOptionsMenu(true); // Create the main contacts adapter mAdapter = new ContactsAdapter(getActivity()); if (savedInstanceState != null) { // If we're restoring state after this fragment was recreated then // retrieve previous search term and previously selected search // result. mSearchTerm = savedInstanceState.getString(SearchManager.QUERY); mPreviouslySelectedSearchItem = savedInstanceState.getInt(STATE_PREVIOUSLY_SELECTED_KEY, 0); } iHomeActionListener = (ActivityHome) getActivity(); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the list fragment layout View view = inflater.inflate(R.layout.contact_list_fragment, container, false); mListContact = (ListView) view.findViewById(R.id.list_contacts); mTextNoContact = (TextView) view.findViewById(R.id.text_no_contact); return view; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mListContact.setAdapter(mAdapter); mListContact.setOnItemClickListener(this); mListContact.setOnItemLongClickListener(this); if (mIsTwoPaneLayout) { // In a two-pane layout, set choice mode to single as there will be two panes // when an item in the ListView is selected it should remain highlighted while // the content shows in the second pane. mListContact.setChoiceMode(ListView.CHOICE_MODE_SINGLE); } // If there's a previously selected search item from a saved state then don't bother // initializing the loader as it will be restarted later when the query is populated into // the action bar search view (see onQueryTextChange() in onCreateOptionsMenu()). if (mPreviouslySelectedSearchItem == 0) { // Initialize the loader, and create a loader identified by ContactsQuery.QUERY_ID getLoaderManager().initLoader(ContactsQuery.QUERY_ID, null, this); } initQuickAction(); } private void initQuickAction() { String editTitle = getActivity().getString(R.string.edit); String deleteTitle = getActivity().getString(R.string.delete); String favouriteTitle = getActivity().getString(R.string.favourite); String shareTitle = getActivity().getString(R.string.share); ActionItem editAction = new ActionItem(); editAction.setTitle(editTitle); editAction.setIcon(getResources().getDrawable(R.drawable.ic_action_edit)); ActionItem deleteAction = new ActionItem(); deleteAction.setTitle(deleteTitle); deleteAction.setIcon(getResources().getDrawable(R.drawable.delete_button)); ActionItem favouriteAction = new ActionItem(); favouriteAction.setTitle(favouriteTitle); favouriteAction.setIcon(getResources().getDrawable(R.drawable.ic_star_outline_grey600_24dp)); ActionItem shareAction = new ActionItem(); shareAction.setTitle(shareTitle); shareAction.setIcon(getResources().getDrawable(R.drawable.ic_share_variant_grey600_48dp)); mQuickAction = new QuickAction(getActivity()); mQuickAction.addActionItem(editAction); mQuickAction.addActionItem(deleteAction); mQuickAction.addActionItem(favouriteAction); mQuickAction.addActionItem(shareAction); // setup the action item click listener mQuickAction.setOnActionItemClickListener(new QuickAction.OnActionItemClickListener() { @Override public void onItemClick(int pos) { switch (pos) { case 0: editThisContact(mSelectedPosition); break; case 1: deleteThisContact(mSelectedPosition); break; case 2: updateThisContactFavourite(mSelectedPosition); break; case 3: shareThisContactAction(mSelectedPosition); break; default: break; } } }); mQuickAction.setOnDismissListener(new OnDismissListener() { @Override public void onDismiss() { mIsOnItemLongClick = false; } }); } private void shareThisContactAction(int selectedPosition) { Cursor cursor = mAdapter.getCursor(); // Moves to the Cursor row corresponding to the ListView item that was clicked cursor.moveToPosition(selectedPosition); String contactId = cursor.getString(ContactsQuery.ID); if (StringUtility.isEmpty(contactId)) return; ArrayList<String> phones = Utils.getContactUriTypeFromContactId(getActivity().getContentResolver(), contactId); String phone = ""; if (phones == null || phones.size() == 0) { phone = ""; } else phone = phones.get(0); String displayName = cursor.getString(ContactsQuery.DISPLAY_NAME); Resources res = getActivity().getResources(); StringBuilder builder = new StringBuilder(); if (!phone.equals(displayName)) builder.append(res.getString(R.string.name)).append(displayName + "\n"); if (!StringUtility.isEmpty(phone)) { builder.append(res.getString(R.string.phone_no)).append(phone); } Intent sharingIntent = new Intent(android.content.Intent.ACTION_SEND); sharingIntent.setType("text/plain"); sharingIntent.putExtra(android.content.Intent.EXTRA_SUBJECT, res.getString(R.string.share_contact)); sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, builder.toString()); startActivity(Intent.createChooser(sharingIntent, displayName)); } @Override public void refreshUI() { super.refreshUI(); mAdapter.notifyDataSetChanged(); } // This method will check this contact is favourite contact or not first, // the checking action includes checking in the contact app. After that, it will add or // remove (if the contact is already existed in favourites) in the contact and my call recorder database application private void updateThisContactFavourite(int selectedPosition) { final Cursor cursor = mAdapter.getCursor(); Resources res = getActivity().getResources(); if (cursor == null) return; // Moves to the Cursor row corresponding to the ListView item that was clicked cursor.moveToPosition(selectedPosition); if (mSQLiteHelper == null) { mSQLiteHelper = MyCallRecorderApplication.getInstance().getSQLiteHelper(getActivity()); } String contactId = cursor.getString(ContactsQuery.ID); if (StringUtility.isEmpty(contactId)) return; ArrayList<String> phones = Utils.getContactUriTypeFromContactId(getActivity().getContentResolver(), contactId); String phoneNo = ""; if (phones == null || phones.size() == 0) { phoneNo = ""; } else phoneNo = phones.get(0); String phoneName = cursor.getString(ContactsQuery.DISPLAY_NAME); FavouriteItem favouriteItem = new FavouriteItem(phoneNo, phoneName, 1, contactId); if (Utils.isCheckFavouriteContact(getActivity(), contactId)) { String removedFavouriteContact = res.getString(R.string.removed_from_favourite, phoneName); mSQLiteHelper.deleteFavouriteItem(favouriteItem); Toast.makeText(getActivity(), removedFavouriteContact, Toast.LENGTH_SHORT).show(); } else { String addFavouriteContact = res.getString(R.string.added_to_favourite, phoneName); mSQLiteHelper.addNewFavoriteItem(favouriteItem); Toast.makeText(getActivity(), addFavouriteContact, Toast.LENGTH_SHORT).show(); } if (MyCallRecorderApplication.getInstance().getActivity() != null) { Utils.requestToRefreshView(MyCallRecorderApplication.getInstance().getActivity(), ActivityHome.FRAGMENT_ALL_RECORDING); Utils.requestToRefreshView(MyCallRecorderApplication.getInstance().getActivity(), ActivityHome.FRAGMENT_FAVOURITE); } mAdapter.notifyDataSetChanged(); } private void deleteThisContact(int selectedPosition) { String deleteTitle = getActivity().getString(R.string.delete); String contentMsg = getActivity().getString(R.string.are_you_sure_to_delete_contact); String cancel = getActivity().getString(R.string.cancel); final Cursor cursor = mAdapter.getCursor(); if (cursor == null) return; // Moves to the Cursor row corresponding to the ListView item that was clicked cursor.moveToPosition(selectedPosition); // Creates a contact lookup Uri from contact ID and lookup_key final Uri uri = Contacts.getLookupUri(cursor.getLong(ContactsQuery.ID), cursor.getString(ContactsQuery.LOOKUP_KEY)); Dialog dialog = new Dialog(getActivity(), deleteTitle, contentMsg); dialog.addCancelButton(cancel, new OnClickListener() { @Override public void onClick(View v) { } }); dialog.setOnAcceptButtonClickListener(new OnClickListener() { @Override public void onClick(View v) { Utils.deleteContact(getActivity(), uri); } }); dialog.getButtonAccept(); dialog.show(); } private void editThisContact(int selectedPosition) { final Cursor cursor = mAdapter.getCursor(); if (cursor == null) return; cursor.moveToPosition(selectedPosition); final Uri uri = Contacts.getLookupUri(cursor.getLong(ContactsQuery.ID), cursor.getString(ContactsQuery.LOOKUP_KEY)); // Standard system edit contact intent Intent intent = new Intent(Intent.ACTION_EDIT, uri); intent.putExtra("finishActivityOnSaveCompleted", true); // Start the edit activity startActivity(intent); } @Override public void onAttach(Activity activity) { super.onAttach(activity); } @Override public void onPause() { super.onPause(); } @Override public void onItemClick(AdapterView<?> parent, View v, int position, long id) { // Gets the Cursor object currently bound to the ListView if (mIsOnItemLongClick) { mIsOnItemLongClick = false; return; } final Cursor cursor = mAdapter.getCursor(); // Moves to the Cursor row corresponding to the ListView item that was clicked cursor.moveToPosition(position); // Creates a contact lookup Uri from contact ID and lookup_key final Uri uri = Contacts.getLookupUri(cursor.getLong(ContactsQuery.ID), cursor.getString(ContactsQuery.LOOKUP_KEY)); Intent intent = new Intent(Intent.ACTION_VIEW, uri); startActivity(intent); if (mIsTwoPaneLayout) { mListContact.setItemChecked(position, true); } } /** * Called when ListView selection is cleared, for example * when search mode is finished and the currently selected * contact should no longer be selected. */ private void onSelectionCleared() { // Uses callback to notify activity this contains this fragment mOnContactSelectedListener.onSelectionCleared(); // Clears currently checked item mListContact.clearChoices(); } @Override public void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); if (!TextUtils.isEmpty(mSearchTerm)) { // Saves the current search string outState.putString(SearchManager.QUERY, mSearchTerm); // Saves the currently selected contact outState.putInt(STATE_PREVIOUSLY_SELECTED_KEY, mListContact.getCheckedItemPosition()); } } @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { // If this is the loader for finding contacts in the Contacts Provider // (the only one supported) if (id == ContactsQuery.QUERY_ID) { Uri contentUri; // There are two types of searches, one which displays all contacts and // one which filters contacts by a search query. If mSearchTerm is set // then a search query has been entered and the latter should be used. if (mSearchTerm == null) { // Since there's no search string, use the content URI that searches the entire // Contacts table contentUri = ContactsQuery.CONTENT_URI; } else { // Since there's a search string, use the special content Uri that searches the // Contacts table. The URI consists of a base Uri and the search string. contentUri = Uri.withAppendedPath(ContactsQuery.FILTER_URI, Uri.encode(mSearchTerm)); } // Returns a new CursorLoader for querying the Contacts table. No arguments are used // for the selection clause. The search string is either encoded onto the content URI, // or no contacts search string is used. The other search criteria are constants. See // the ContactsQuery interface. return new CursorLoader(getActivity(), contentUri, ContactsQuery.PROJECTION, ContactsQuery.SELECTION, null, ContactsQuery.SORT_ORDER); } return null; } @Override public void onLoadFinished(Loader<Cursor> loader, Cursor data) { // This swaps the new cursor into the adapter. if (loader.getId() == ContactsQuery.QUERY_ID) { mAdapter.swapCursor(data); // If this is a two-pane layout and there is a search query then // there is some additional work to do around default selected // search item. if (mIsTwoPaneLayout && !TextUtils.isEmpty(mSearchTerm) && mSearchQueryChanged) { // Selects the first item in results, unless this fragment has // been restored from a saved state (like orientation change) // in which case it selects the previously selected search item. if (data != null && data.moveToPosition(mPreviouslySelectedSearchItem)) { // Creates the content Uri for the previously selected contact by appending the // contact's ID to the Contacts table content Uri final Uri uri = Uri.withAppendedPath(Contacts.CONTENT_URI, String.valueOf(data.getLong(ContactsQuery.ID))); mOnContactSelectedListener.onContactSelected(uri); mListContact.setItemChecked(mPreviouslySelectedSearchItem, true); } else { // No results, clear selection. onSelectionCleared(); } // Only restore from saved state one time. Next time fall back // to selecting first item. If the fragment state is saved again // then the currently selected item will once again be saved. mPreviouslySelectedSearchItem = 0; mSearchQueryChanged = false; } } } @Override public void onLoaderReset(Loader<Cursor> loader) { if (loader.getId() == ContactsQuery.QUERY_ID) { // When the loader is being reset, clear the cursor from the adapter. This allows the // cursor resources to be freed. mAdapter.swapCursor(null); } } /** * This is a subclass of CursorAdapter that supports binding Cursor columns to a view layout. * If those items are part of search results, the search string is marked by highlighting the * query text. An {@link AlphabetIndexer} is used to allow quicker navigation up and down the * ListView. */ private class ContactsAdapter extends CursorAdapter implements SectionIndexer { private LayoutInflater mInflater; // Stores the layout inflater private AlphabetIndexer mAlphabetIndexer; // Stores the AlphabetIndexer instance private TextAppearanceSpan highlightTextSpan; // Stores the highlight text appearance style private int mThemeColor; /** * Instantiates a new Contacts Adapter. * @param context A context that has access to the app's layout. */ public ContactsAdapter(Context context) { super(context, null, 0); // Stores inflater for use later mInflater = LayoutInflater.from(context); final String alphabet = context.getString(R.string.alphabet); mAlphabetIndexer = new AlphabetIndexer(getCursor(), ContactsQuery.SORT_KEY, alphabet); highlightTextSpan = new TextAppearanceSpan(getActivity(), R.style.searchTextHiglight); mThemeColor = MyCallRecorderApplication.getInstance().getApplicationTheme(); } public void onClickCallContact(int position) { Cursor cursor = mAdapter.getCursor(); // Moves to the Cursor row corresponding to the ListView item that was clicked cursor.moveToPosition(position); String contactId = cursor.getString(ContactsQuery.ID); if (StringUtility.isEmpty(contactId)) return; ArrayList<String> phones = Utils.getContactUriTypeFromContactId(getActivity().getContentResolver(), contactId); if (phones == null || phones.size() == 0) { Toast.makeText(getActivity(), "No phone number", Toast.LENGTH_SHORT).show(); return; } Intent intent = new Intent(Intent.ACTION_CALL); intent.setData(Uri.parse("tel:" + phones.get(0))); startActivity(intent); } /** * Identifies the start of the search string in the display name column of a Cursor row. * E.g. If displayName was "Adam" and search query (mSearchTerm) was "da" this would * return 1. * * @param displayName The contact display name. * @return The starting position of the search string in the display name, 0-based. The * method returns -1 if the string is not found in the display name, or if the search * string is empty or null. */ private int indexOfSearchQuery(String displayName) { if (!TextUtils.isEmpty(mSearchTerm)) { return displayName.toLowerCase(Locale.getDefault()) .indexOf(mSearchTerm.toLowerCase(Locale.getDefault())); } return -1; } /** * Overrides newView() to inflate the list item views. */ @Override public View newView(Context context, Cursor cursor, ViewGroup viewGroup) { final View itemLayout = mInflater.inflate(R.layout.contact_list_item, viewGroup, false); final ViewHolder holder = new ViewHolder(); holder.textAlphabet = (TextView) itemLayout.findViewById(R.id.text_alphabet_character); holder.textPhoneName = (TextView) itemLayout.findViewById(R.id.text_phone_name); holder.textPhoneName.setSelected(true); holder.textMatchOtherField = (TextView) itemLayout.findViewById(R.id.text_match_other_field); holder.icon = (CircleImageView) itemLayout.findViewById(android.R.id.icon); holder.divider = (View) itemLayout.findViewById(R.id.divider); holder.btnButton = (Button) itemLayout.findViewById(R.id.btn_call); holder.icStar = (ImageView) itemLayout.findViewById(R.id.ic_star); holder.dividerCall = (View) itemLayout.findViewById(R.id.divider_call); itemLayout.setTag(holder); // Returns the item layout view return itemLayout; } /** * Binds data from the Cursor to the provided view. */ @Override public void bindView(View view, Context context, final Cursor cursor) { // Gets handles to individual view resources final ViewHolder holder = (ViewHolder) view.getTag(); // For Android 3.0 and later, gets the thumbnail image Uri from the current Cursor row. // For platforms earlier than 3.0, this isn't necessary, because the thumbnail is // generated from the other fields in the row. if (getCount() == 0) { mTextNoContact.setVisibility(View.VISIBLE); } else mTextNoContact.setVisibility(View.GONE); final String photoUri = cursor.getString(ContactsQuery.PHOTO_THUMBNAIL_DATA); final String contactId = cursor.getString(ContactsQuery.ID); final String displayName = cursor.getString(ContactsQuery.DISPLAY_NAME); final int startIndex = indexOfSearchQuery(displayName); final int position = cursor.getPosition(); final int sessionPosition = mAlphabetIndexer.getSectionForPosition(cursor.getPosition()); int positionOfSession = mAlphabetIndexer.getPositionForSection(sessionPosition); if (positionOfSession == cursor.getPosition()) { holder.textAlphabet.setVisibility(View.VISIBLE); holder.divider.setVisibility(View.VISIBLE); holder.divider.setBackgroundColor(mThemeColor); final String alphabet = context.getString(R.string.alphabet); char alphabetCharacter = alphabet.charAt(sessionPosition); holder.textAlphabet.setText(alphabetCharacter + ""); holder.textAlphabet.setTextColor(mThemeColor); } else { holder.divider.setVisibility(View.GONE); holder.textAlphabet.setVisibility(View.GONE); } if (startIndex == -1) { holder.textPhoneName.setText(displayName); if (TextUtils.isEmpty(mSearchTerm)) { holder.textMatchOtherField.setVisibility(View.GONE); } else { holder.textMatchOtherField.setVisibility(View.VISIBLE); } } else { final SpannableString highlightedName = new SpannableString(displayName); highlightedName.setSpan(highlightTextSpan, startIndex, startIndex + mSearchTerm.length(), 0); holder.textPhoneName.setText(highlightedName); holder.textMatchOtherField.setVisibility(View.GONE); } final Uri contactUri = Contacts.getLookupUri(cursor.getLong(ContactsQuery.ID), cursor.getString(ContactsQuery.LOOKUP_KEY)); if (photoUri != null) { holder.icon.setImageURI(Uri.parse(photoUri)); } else { holder.icon.setImageResource(R.drawable.ic_contact_picture_holo_light); } holder.icon.assignContactUri(contactUri); ArrayList<String> phones = Utils.getContactUriTypeFromContactId(getActivity().getContentResolver(), contactId); String phoneNo = ""; if (phones == null || phones.size() == 0) { phoneNo = ""; } else phoneNo = phones.get(0); if ("".equals(phoneNo)) { holder.btnButton.setVisibility(View.GONE); holder.dividerCall.setVisibility(View.GONE); } else { holder.btnButton.setVisibility(View.VISIBLE); holder.dividerCall.setVisibility(View.VISIBLE); holder.dividerCall.setBackgroundColor(mThemeColor); } holder.btnButton.setFocusable(false); holder.dividerCall.setFocusable(false); holder.divider.setFocusable(false); holder.btnButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { onClickCallContact(position); } }); boolean isFavourite = Utils.isCheckFavouriteContact(getActivity(), contactId); if (isFavourite) holder.icStar.setVisibility(View.VISIBLE); else holder.icStar.setVisibility(View.GONE); } /** * Overrides swapCursor to move the new Cursor into the AlphabetIndex as well as the * CursorAdapter. */ @Override public Cursor swapCursor(Cursor newCursor) { // Update the AlphabetIndexer with new cursor as well mAlphabetIndexer.setCursor(newCursor); return super.swapCursor(newCursor); } /** * An override of getCount that simplifies accessing the Cursor. If the Cursor is null, * getCount returns zero. As a result, no test for Cursor == null is needed. */ @Override public int getCount() { if (getCursor() == null) { return 0; } return super.getCount(); } /** * Defines the SectionIndexer.getSections() interface. */ @Override public Object[] getSections() { return mAlphabetIndexer.getSections(); } /** * Defines the SectionIndexer.getPositionForSection() interface. */ @Override public int getPositionForSection(int i) { if (getCursor() == null) { return 0; } return mAlphabetIndexer.getPositionForSection(i); } /** * Defines the SectionIndexer.getSectionForPosition() interface. */ @Override public int getSectionForPosition(int i) { if (getCursor() == null) { return 0; } return mAlphabetIndexer.getSectionForPosition(i); } /** * A class that defines fields for each resource ID in the list item layout. This allows * ContactsAdapter.newView() to store the IDs once, when it inflates the layout, instead of * calling findViewById in each iteration of bindView. */ private class ViewHolder { TextView textAlphabet; TextView textPhoneName; TextView textMatchOtherField; CircleImageView icon; View divider; ImageView icStar; View dividerCall; Button btnButton; } public void updateTheme(int themeColor, int pressThemeColor) { mThemeColor = themeColor; } } /** * This interface must be implemented by any activity that loads this fragment. When an * interaction occurs, such as touching an item from the ListView, these callbacks will * be invoked to communicate the event back to the activity. */ public interface OnContactsInteractionListener { /** * Called when a contact is selected from the ListView. * @param contactUri The contact Uri. */ public void onContactSelected(Uri contactUri); /** * Called when the ListView selection is cleared like when * a contact search is taking place or is finishing. */ public void onSelectionCleared(); } public void onQueryTextChange(CharSequence s) { String searchText = s == null ? "" : s.toString(); mSearchTerm = searchText; // In version 3.0 and later, sets up and configures the ActionBar SearchView if (Utils.hasHoneycomb()) { String newFilter = !TextUtils.isEmpty(mSearchTerm) ? mSearchTerm : null; // Don't do anything if the filter is empty if (mSearchTerm == null && newFilter == null) { AIOLog.e(MyCallRecorderConstant.TAG, "newFilter == null"); return; } // Updates current filter to new filter mSearchTerm = newFilter; // necessary content Uri from mSearchTerm. mSearchQueryChanged = true; getLoaderManager().restartLoader(ContactsQuery.QUERY_ID, null, FragmentContact.this); return; } if (Utils.hasICS()) { // When the user collapses the SearchView the current search string is // cleared and the loader restarted. if (!TextUtils.isEmpty(mSearchTerm)) { onSelectionCleared(); } mSearchTerm = null; getLoaderManager().restartLoader(ContactsQuery.QUERY_ID, null, FragmentContact.this); return; } } @Override public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { mIsOnItemLongClick = true; mSelectedPosition = position; CircleImageView image = (CircleImageView) view.findViewById(android.R.id.icon); if (mQuickAction == null) return false; mQuickAction.show(view, image); return false; } public void updateTheme(int themeColor, int pressThemeColor) { mAdapter.updateTheme(themeColor, pressThemeColor); } }