/**
   * Loads data from the content provider, organizes it into {@link RawContactInfo} objects and
   * returns a sorted list of {@link RawContactInfo}'s.
   */
  private List<RawContactInfo> loadData() {
    HashMap<Long, RawContactInfo> rawContactInfos = new HashMap<Long, RawContactInfo>();
    Uri dataUri = Uri.withAppendedPath(mAggregateUri, Data.CONTENT_DIRECTORY);
    Cursor cursor =
        getContext().getContentResolver().query(dataUri, SplitQuery.COLUMNS, null, null, null);
    try {
      while (cursor.moveToNext()) {
        long rawContactId = cursor.getLong(SplitQuery.RAW_CONTACT_ID);
        RawContactInfo info = rawContactInfos.get(rawContactId);
        if (info == null) {
          info = new RawContactInfo(rawContactId);
          rawContactInfos.put(rawContactId, info);
          info.accountType = cursor.getString(SplitQuery.ACCOUNT_TYPE);
          info.dataSet = cursor.getString(SplitQuery.DATA_SET);
        }

        String mimetype = cursor.getString(SplitQuery.MIMETYPE);
        if (StructuredName.CONTENT_ITEM_TYPE.equals(mimetype)) {
          loadStructuredName(cursor, info);
        } else if (Phone.CONTENT_ITEM_TYPE.equals(mimetype)) {
          loadPhoneNumber(cursor, info);
        } else if (Email.CONTENT_ITEM_TYPE.equals(mimetype)) {
          loadEmail(cursor, info);
        } else if (Nickname.CONTENT_ITEM_TYPE.equals(mimetype)) {
          loadNickname(cursor, info);
        }
      }
    } finally {
      cursor.close();
    }

    List<RawContactInfo> list = new ArrayList<RawContactInfo>(rawContactInfos.values());
    Collections.sort(list);
    return list;
  }
  public List<Suggestion> getSuggestions() {
    ArrayList<Suggestion> list = Lists.newArrayList();
    if (mDataCursor != null) {
      Suggestion suggestion = null;
      long currentContactId = -1;
      mDataCursor.moveToPosition(-1);
      while (mDataCursor.moveToNext()) {
        long contactId = mDataCursor.getLong(DataQuery.CONTACT_ID);
        if (contactId != currentContactId) {
          suggestion = new Suggestion();
          suggestion.contactId = contactId;
          suggestion.name = mDataCursor.getString(DataQuery.DISPLAY_NAME);
          suggestion.lookupKey = mDataCursor.getString(DataQuery.LOOKUP_KEY);
          suggestion.rawContacts = Lists.newArrayList();
          list.add(suggestion);
          currentContactId = contactId;
        }

        long rawContactId = mDataCursor.getLong(DataQuery.RAW_CONTACT_ID);
        if (!containsRawContact(suggestion, rawContactId)) {
          RawContact rawContact = new RawContact();
          rawContact.rawContactId = rawContactId;
          rawContact.accountName = mDataCursor.getString(DataQuery.ACCOUNT_NAME);
          rawContact.accountType = mDataCursor.getString(DataQuery.ACCOUNT_TYPE);
          rawContact.dataSet = mDataCursor.getString(DataQuery.DATA_SET);
          suggestion.rawContacts.add(rawContact);
        }

        String mimetype = mDataCursor.getString(DataQuery.MIMETYPE);
        if (Phone.CONTENT_ITEM_TYPE.equals(mimetype)) {
          String data = mDataCursor.getString(DataQuery.DATA1);
          int superprimary = mDataCursor.getInt(DataQuery.IS_SUPERPRIMARY);
          if (!TextUtils.isEmpty(data) && (superprimary != 0 || suggestion.phoneNumber == null)) {
            suggestion.phoneNumber = data;
          }
        } else if (Email.CONTENT_ITEM_TYPE.equals(mimetype)) {
          String data = mDataCursor.getString(DataQuery.DATA1);
          int superprimary = mDataCursor.getInt(DataQuery.IS_SUPERPRIMARY);
          if (!TextUtils.isEmpty(data) && (superprimary != 0 || suggestion.emailAddress == null)) {
            suggestion.emailAddress = data;
          }
        } else if (Nickname.CONTENT_ITEM_TYPE.equals(mimetype)) {
          String data = mDataCursor.getString(DataQuery.DATA1);
          if (!TextUtils.isEmpty(data)) {
            suggestion.nickname = data;
          }
        } else if (Photo.CONTENT_ITEM_TYPE.equals(mimetype)) {
          long dataId = mDataCursor.getLong(DataQuery.ID);
          long photoId = mDataCursor.getLong(DataQuery.PHOTO_ID);
          if (dataId == photoId && !mDataCursor.isNull(DataQuery.PHOTO)) {
            suggestion.photo = mDataCursor.getBlob(DataQuery.PHOTO);
          }
        }
      }
    }
    return list;
  }
    /** Create an action from common {@link Data} elements. */
    public DataAction(Context context, String mimeType, DataKind kind, long dataId, Cursor cursor) {
      mContext = context;
      mKind = kind;
      mMimeType = mimeType;

      // Inflate strings from cursor
      mAlternate = Constants.MIME_SMS_ADDRESS.equals(mimeType);
      if (mAlternate && mKind.actionAltHeader != null) {
        mHeader = mKind.actionAltHeader.inflateUsing(context, cursor);
      } else if (mKind.actionHeader != null) {
        mHeader = mKind.actionHeader.inflateUsing(context, cursor);
      }

      if (getAsInt(cursor, Data.IS_SUPER_PRIMARY) != 0) {
        mIsPrimary = true;
      }

      if (mKind.actionBody != null) {
        mBody = mKind.actionBody.inflateUsing(context, cursor);
      }

      mDataUri = ContentUris.withAppendedId(TData.CONTENT_URI, dataId);

      // Handle well-known MIME-types with special care
      if (Phone.CONTENT_ITEM_TYPE.equals(mimeType)) {
        final String number = getAsString(cursor, Phone.NUMBER);
        if (!TextUtils.isEmpty(number)) {
          final Uri callUri = Uri.fromParts(Constants.SCHEME_TEL, number, null);
          mIntent = new Intent(TIntent.ACTION_CALL_PRIVILEGED, callUri);
        }

      } else if (Constants.MIME_SMS_ADDRESS.equals(mimeType)) {
        final String number = getAsString(cursor, Phone.NUMBER);
        if (!TextUtils.isEmpty(number)) {
          final Uri smsUri = Uri.fromParts(Constants.SCHEME_SMSTO, number, null);
          mIntent = new Intent(TIntent.getACTION_SENDTO(mContext), smsUri);
        }

      } else if (Email.CONTENT_ITEM_TYPE.equals(mimeType)) {
        final String address = getAsString(cursor, Email.DATA);
        if (!TextUtils.isEmpty(address)) {
          final Uri mailUri = Uri.fromParts(Constants.SCHEME_MAILTO, address, null);
          mIntent = new Intent(TIntent.getACTION_SENDTO(mContext), mailUri);
        }

      } else if (Im.CONTENT_ITEM_TYPE.equals(mimeType)) {
        final boolean isEmail = Email.CONTENT_ITEM_TYPE.equals(getAsString(cursor, Data.MIMETYPE));
        if (isEmail || isProtocolValid(cursor)) {
          final int protocol = isEmail ? Im.PROTOCOL_GOOGLE_TALK : getAsInt(cursor, Im.PROTOCOL);

          if (isEmail) {
            // Use Google Talk string when using Email, and clear data
            // Uri so we don't try saving Email as primary.
            mHeader = context.getText(R.string.chat_gtalk);
            mDataUri = null;
          }

          String host = getAsString(cursor, Im.CUSTOM_PROTOCOL);
          String data = getAsString(cursor, isEmail ? Email.DATA : Im.DATA);
          if (protocol != Im.PROTOCOL_CUSTOM) {
            // Try bringing in a well-known host for specific protocols
            host = ContactsUtils.lookupProviderNameFromId(protocol);
          }

          if (!TextUtils.isEmpty(host) && !TextUtils.isEmpty(data)) {
            final String authority = host.toLowerCase();
            final Uri imUri =
                new Uri.Builder()
                    .scheme(Constants.SCHEME_IMTO)
                    .authority(authority)
                    .appendPath(data)
                    .build();
            mIntent = new Intent(TIntent.getACTION_SENDTO(mContext), imUri);
          }
        }
      }

      if (mIntent == null) {
        // Otherwise fall back to default VIEW action
        mIntent = new Intent(TIntent.ACTION_VIEW, mDataUri);
      }

      // Always launch as new task, since we're like a launcher
      mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
    }
  /** Handle the result from the {@link #TOKEN_DATA} query. */
  private void handleData(Cursor cursor) {
    if (cursor == null) return;

    if (!isMimeExcluded(Contacts.CONTENT_ITEM_TYPE)) {
      // Add the profile shortcut action
      final Action action = new ProfileAction(mContext, mLookupUri);
      mActions.collect(Contacts.CONTENT_ITEM_TYPE, action);
    }

    final DataStatus status = new DataStatus();
    final Sources sources = Sources.getInstance(mContext);
    final ImageView photoView = (ImageView) mHeader.findViewById(R.id.photo);

    Bitmap photoBitmap = null;
    while (cursor.moveToNext()) {
      final long dataId = cursor.getLong(DataQuery._ID);
      final String accountType = cursor.getString(DataQuery.ACCOUNT_TYPE);
      final String mimeType = cursor.getString(DataQuery.MIMETYPE);

      // Handle any social status updates from this row
      status.possibleUpdate(cursor);

      // Skip this data item if MIME-type excluded
      if (isMimeExcluded(mimeType)) continue;

      // Handle photos included as data row
      if (Photo.CONTENT_ITEM_TYPE.equals(mimeType)) {
        final int colPhoto = cursor.getColumnIndex(Photo.PHOTO);
        final byte[] photoBlob = cursor.getBlob(colPhoto);
        if (photoBlob != null) {
          photoBitmap = BitmapFactory.decodeByteArray(photoBlob, 0, photoBlob.length);
        }
        continue;
      }

      final DataKind kind =
          sources.getKindOrFallback(
              accountType, mimeType, mContext, ContactsSource.LEVEL_MIMETYPES);

      if (kind != null) {
        // Build an action for this data entry, find a mapping to a UI
        // element, build its summary from the cursor, and collect it
        // along with all others of this MIME-type.
        final Action action = new DataAction(mContext, mimeType, kind, dataId, cursor);
        considerAdd(action, mimeType);
      }

      // If phone number, also insert as text message action
      if (Phone.CONTENT_ITEM_TYPE.equals(mimeType) && kind != null) {
        final Action action =
            new DataAction(mContext, Constants.MIME_SMS_ADDRESS, kind, dataId, cursor);
        considerAdd(action, Constants.MIME_SMS_ADDRESS);
      }

      // Handle Email rows with presence data as Im entry
      final boolean hasPresence = !cursor.isNull(DataQuery.PRESENCE);
      if (hasPresence && Email.CONTENT_ITEM_TYPE.equals(mimeType)) {
        final DataKind imKind =
            sources.getKindOrFallback(
                accountType, Im.CONTENT_ITEM_TYPE, mContext, ContactsSource.LEVEL_MIMETYPES);
        if (imKind != null) {
          final Action action =
              new DataAction(mContext, Im.CONTENT_ITEM_TYPE, imKind, dataId, cursor);
          considerAdd(action, Im.CONTENT_ITEM_TYPE);
        }
      }
    }

    if (cursor.moveToLast()) {
      // Read contact information from last data row
      final String name = cursor.getString(DataQuery.DISPLAY_NAME);
      final int presence = cursor.getInt(DataQuery.CONTACT_PRESENCE);
      final Drawable statusIcon = getPresenceIcon(presence);

      setHeaderText(R.id.name, name);
      setHeaderImage(R.id.presence, statusIcon);
    }

    if (photoView != null) {
      // Place photo when discovered in data, otherwise hide
      photoView.setVisibility(photoBitmap != null ? View.VISIBLE : View.GONE);
      photoView.setImageBitmap(photoBitmap);
    }

    mHasValidSocial = status.isValid();
    if (mHasValidSocial && mMode != QuickContact.MODE_SMALL) {
      // Update status when valid was found
      setHeaderText(R.id.status, status.getStatus());
      setHeaderText(R.id.timestamp, status.getTimestampLabel(mContext));
    }

    // Turn our list of actions into UI elements, starting with common types
    final Set<String> containedTypes = mActions.keySet();
    for (String mimeType : ORDERED_MIMETYPES) {
      if (containedTypes.contains(mimeType)) {
        final int index = mTrack.getChildCount() - 1;
        mTrack.addView(inflateAction(mimeType), index);
        containedTypes.remove(mimeType);
      }
    }

    // Then continue with remaining MIME-types in alphabetical order
    final String[] remainingTypes = containedTypes.toArray(new String[containedTypes.size()]);
    Arrays.sort(remainingTypes);
    for (String mimeType : remainingTypes) {
      final int index = mTrack.getChildCount() - 1;
      mTrack.addView(inflateAction(mimeType), index);
    }
  }