@Override
  public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {

        // For platforms earlier than Android 3.0, triggers the search activity
      case R.id.menu_search:
        if (!Utils.hasHoneycomb()) {
          getActivity().onSearchRequested();
        }
        break;
    }
    return super.onOptionsItemSelected(item);
  }
  /**
   * This interface defines constants for the Cursor and CursorLoader, based on constants defined in
   * the {@link android.provider.ContactsContract.Contacts} class.
   */
  public interface ContactsQuery {

    // An identifier for the loader
    static final int QUERY_ID = 1;

    // A content URI for the Contacts table
    static final Uri CONTENT_URI = Contacts.CONTENT_URI;

    // The search/filter query Uri
    static final Uri FILTER_URI = Contacts.CONTENT_FILTER_URI;

    // The selection clause for the CursorLoader query. The search criteria
    // defined here
    // restrict results to contacts that have a display name and are linked
    // to visible groups.
    // Notice that the search on the string provided by the user is
    // implemented by appending
    // the search string to CONTENT_FILTER_URI.
    @SuppressLint("InlinedApi")
    static final String SELECTION =
        (Utils.hasHoneycomb() ? Contacts.DISPLAY_NAME_PRIMARY : Contacts.DISPLAY_NAME)
            + "<>''"
            + " AND "
            + Contacts.IN_VISIBLE_GROUP
            + "=1";

    // The desired sort order for the returned Cursor. In Android 3.0 and
    // later, the primary
    // sort key allows for localization. In earlier versions. use the
    // display name as the sort
    // key.
    @SuppressLint("InlinedApi")
    static final String SORT_ORDER =
        Utils.hasHoneycomb() ? Contacts.SORT_KEY_PRIMARY : Contacts.DISPLAY_NAME;

    // The projection for the CursorLoader query. This is a list of columns
    // that the Contacts
    // Provider should return in the Cursor.
    @SuppressLint("InlinedApi")
    static final String[] PROJECTION = {

      // The contact's row id
      Contacts._ID,

      // A pointer to the contact that is guaranteed to be more
      // permanent than _ID. Given
      // a contact's current _ID value and LOOKUP_KEY, the Contacts
      // Provider can generate
      // a "permanent" contact URI.
      Contacts.LOOKUP_KEY,

      // In platform version 3.0 and later, the Contacts table
      // contains
      // DISPLAY_NAME_PRIMARY, which either contains the contact's
      // displayable name or
      // some other useful identifier such as an email address. This
      // column isn't
      // available in earlier versions of Android, so you must use
      // Contacts.DISPLAY_NAME
      // instead.
      Utils.hasHoneycomb() ? Contacts.DISPLAY_NAME_PRIMARY : Contacts.DISPLAY_NAME,

      // In Android 3.0 and later, the thumbnail image is pointed to
      // by
      // PHOTO_THUMBNAIL_URI. In earlier versions, there is no direct
      // pointer; instead,
      // you generate the pointer from the contact's ID value and
      // constants defined in
      // android.provider.ContactsContract.Contacts.
      Utils.hasHoneycomb() ? Contacts.PHOTO_THUMBNAIL_URI : Contacts._ID,

      // The sort order column for the returned Cursor, used by the
      // AlphabetIndexer
      SORT_ORDER,
    };

    // The query column numbers which map to each value in the projection
    static final int ID = 0;
    static final int LOOKUP_KEY = 1;
    static final int DISPLAY_NAME = 2;
    static final int PHOTO_THUMBNAIL_DATA = 3;
    static final int SORT_KEY = 4;
  }
  /**
   * Decodes and scales a contact's image from a file pointed to by a Uri in the contact's data, and
   * returns the result as a Bitmap. The column that contains the Uri varies according to the
   * platform version.
   *
   * @param photoData For platforms prior to Android 3.0, provide the Contact._ID column value. For
   *     Android 3.0 and later, provide the Contact.PHOTO_THUMBNAIL_URI value.
   * @param imageSize The desired target width and height of the output image in pixels.
   * @return A Bitmap containing the contact's image, resized to fit the provided image size. If no
   *     thumbnail exists, returns null.
   */
  private Bitmap loadContactPhotoThumbnail(String photoData, int imageSize) {

    // Ensures the Fragment is still added to an activity. As this method is
    // called in a
    // background thread, there's the possibility the Fragment is no longer
    // attached and
    // added to an activity. If so, no need to spend resources loading the
    // contact photo.
    if (!isAdded() || getActivity() == null) {
      return null;
    }

    // Instantiates an AssetFileDescriptor. Given a content Uri pointing to
    // an image file, the
    // ContentResolver can return an AssetFileDescriptor for the file.
    AssetFileDescriptor afd = null;

    // This "try" block catches an Exception if the file descriptor returned
    // from the Contacts
    // Provider doesn't point to an existing file.
    try {
      Uri thumbUri;
      // If Android 3.0 or later, converts the Uri passed as a string to a
      // Uri object.
      if (Utils.hasHoneycomb()) {
        thumbUri = Uri.parse(photoData);
      } else {
        // For versions prior to Android 3.0, appends the string
        // argument to the content
        // Uri for the Contacts table.
        final Uri contactUri = Uri.withAppendedPath(Contacts.CONTENT_URI, photoData);

        // Appends the content Uri for the Contacts.Photo table to the
        // previously
        // constructed contact Uri to yield a content URI for the
        // thumbnail image
        thumbUri = Uri.withAppendedPath(contactUri, Photo.CONTENT_DIRECTORY);
      }
      // Retrieves a file descriptor from the Contacts Provider. To learn
      // more about this
      // feature, read the reference documentation for
      // ContentResolver#openAssetFileDescriptor.
      afd = getActivity().getContentResolver().openAssetFileDescriptor(thumbUri, "r");

      // Gets a FileDescriptor from the AssetFileDescriptor. A
      // BitmapFactory object can
      // decode the contents of a file pointed to by a FileDescriptor into
      // a Bitmap.
      FileDescriptor fileDescriptor = afd.getFileDescriptor();

      if (fileDescriptor != null) {
        // Decodes a Bitmap from the image pointed to by the
        // FileDescriptor, and scales it
        // to the specified width and height
        return ImageLoader.decodeSampledBitmapFromDescriptor(fileDescriptor, imageSize, imageSize);
      }
    } catch (FileNotFoundException e) {
      // If the file pointed to by the thumbnail URI doesn't exist, or the
      // file can't be
      // opened in "read" mode, ContentResolver.openAssetFileDescriptor
      // throws a
      // FileNotFoundException.
      if (BuildConfig.DEBUG) {
        Log.d(
            TAG,
            "Contact photo thumbnail not found for contact " + photoData + ": " + e.toString());
      }
    } finally {
      // If an AssetFileDescriptor was returned, try to close it
      if (afd != null) {
        try {
          afd.close();
        } catch (IOException e) {
          // Closing a file descriptor might cause an IOException if
          // the file is
          // already closed. Nothing extra is needed to handle this.
        }
      }
    }

    // If the decoding failed, returns null
    return null;
  }
  // This method uses APIs from newer OS versions than the minimum that this
  // app supports. This
  // annotation tells Android lint that they are properly guarded so they
  // won't run on older OS
  // versions and can be ignored by lint.
  @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
  @Override
  public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {

    // Inflate the menu items
    inflater.inflate(R.menu.contacts_list_menu, menu);
    // Locate the search item
    MenuItem searchItem = menu.findItem(R.id.menu_search);

    // In versions prior to Android 3.0, hides the search item to prevent
    // additional
    // searches. In Android 3.0 and later, searching is done via a
    // SearchView in the ActionBar.
    // Since the search doesn't create a new Activity to do the searching,
    // the menu item
    // doesn't need to be turned off.
    if (mIsSearchResultView) {
      searchItem.setVisible(false);
    }

    // In version 3.0 and later, sets up and configures the ActionBar
    // SearchView
    if (Utils.hasHoneycomb()) {

      // Retrieves the system search manager service
      final SearchManager searchManager =
          (SearchManager) getActivity().getSystemService(Context.SEARCH_SERVICE);

      // Retrieves the SearchView from the search menu item
      final SearchView searchView = (SearchView) searchItem.getActionView();

      // Assign searchable info to SearchView
      searchView.setSearchableInfo(
          searchManager.getSearchableInfo(getActivity().getComponentName()));

      // Set listeners for SearchView
      searchView.setOnQueryTextListener(
          new SearchView.OnQueryTextListener() {
            @Override
            public boolean onQueryTextSubmit(String queryText) {
              // Nothing needs to happen when the user submits the
              // search string
              return true;
            }

            @Override
            public boolean onQueryTextChange(String newText) {
              // Called when the action bar search text has
              // changed. Updates
              // the search filter, and restarts the loader to do
              // a new query
              // using the new search string.
              String newFilter = !TextUtils.isEmpty(newText) ? newText : null;

              // Don't do anything if the filter is empty
              if (mSearchTerm == null && newFilter == null) {
                return true;
              }

              // Don't do anything if the new filter is the same
              // as the current filter
              if (mSearchTerm != null && mSearchTerm.equals(newFilter)) {
                return true;
              }

              // Updates current filter to new filter
              mSearchTerm = newFilter;

              // Restarts the loader. This triggers
              // onCreateLoader(), which builds the
              // necessary content Uri from mSearchTerm.
              mSearchQueryChanged = true;
              getLoaderManager()
                  .restartLoader(ContactsQuery.QUERY_ID, null, ContactsListFragment.this);
              return true;
            }
          });

      if (Utils.hasICS()) {
        // This listener added in ICS
        searchItem.setOnActionExpandListener(
            new MenuItem.OnActionExpandListener() {
              @Override
              public boolean onMenuItemActionExpand(MenuItem menuItem) {
                // Nothing to do when the action item is
                // expanded
                return true;
              }

              @Override
              public boolean onMenuItemActionCollapse(MenuItem menuItem) {
                // 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, ContactsListFragment.this);
                return true;
              }
            });
      }

      if (mSearchTerm != null) {
        // If search term is already set here then this fragment is
        // being restored from a saved state and the search menu item
        // needs to be expanded and populated again.

        // Stores the search term (as it will be wiped out by
        // onQueryTextChange() when the menu item is expanded).
        final String savedSearchTerm = mSearchTerm;

        // Expands the search menu item
        if (Utils.hasICS()) {
          searchItem.expandActionView();
        }

        // Sets the SearchView to the previous search string
        searchView.setQuery(savedSearchTerm, false);
      }
    }
  }