/**
   * Set outgoing group chat message or file to delivered
   *
   * @param chatId Group chat ID
   * @param contact The contact ID for which the entry is to be updated
   * @param msgId Message ID
   * @param timestampDelivered Time for delivery
   */
  public boolean setGroupChatDeliveryInfoDelivered(
      String chatId, ContactId contact, String msgId, long timestampDelivered) {
    GroupDeliveryInfo.Status status = GroupDeliveryInfo.Status.DELIVERED;
    GroupDeliveryInfo.ReasonCode reason = GroupDeliveryInfo.ReasonCode.UNSPECIFIED;

    ContentValues values = new ContentValues();
    values.put(GroupDeliveryInfoData.KEY_STATUS, status.toInt());
    values.put(GroupDeliveryInfoData.KEY_TIMESTAMP_DELIVERED, timestampDelivered);
    values.put(GroupDeliveryInfoData.KEY_REASON_CODE, reason.toInt());
    String[] selectionArgs = new String[] {msgId, contact.toString()};

    if (mLocalContentResolver.update(
            GroupDeliveryInfoData.CONTENT_URI,
            values,
            SELECTION_DELIVERY_INFO_BY_MSG_ID_AND_CONTACT_EXCLUDE_DISPLAYED,
            selectionArgs)
        > 0) {
      /* A matching GDI row was found and updated. */
      return true;
    }

    Cursor cursor = null;
    try {
      Uri contentUri = GroupDeliveryInfoData.CONTENT_URI;
      cursor =
          mLocalContentResolver.query(
              contentUri,
              PROJECTION_MESSAGE_ID,
              SELECTION_DELIVERY_INFO_BY_MSG_ID_AND_CONTACT,
              selectionArgs,
              null);
      CursorUtil.assertCursorIsNotNull(cursor, contentUri);
      if (cursor.getCount() < 1) {
        /*
         * No entry updated means that there was no matching row. Adding row and setting
         * displayed timestamp to 0.
         */
        addGroupChatDeliveryInfoEntry(
            chatId, contact, msgId, status, reason, timestampDelivered, 0);
        return true;
      }
      /*
       * A matching row was found but since it was not already updated above we can assume it
       * shouldn't be updated.
       */
      return false;
    } finally {
      CursorUtil.close(cursor);
    }
  }
  @Override
  public boolean setGroupChatDeliveryInfoDisplayed(
      String chatId, ContactId contact, String msgId, long timestampDisplayed) {
    ContentValues values = new ContentValues();
    GroupDeliveryInfo.Status status = GroupDeliveryInfo.Status.DISPLAYED;
    GroupDeliveryInfo.ReasonCode reason = GroupDeliveryInfo.ReasonCode.UNSPECIFIED;

    values.put(GroupDeliveryInfoData.KEY_STATUS, status.toInt());
    values.put(GroupDeliveryInfoData.KEY_TIMESTAMP_DISPLAYED, timestampDisplayed);
    values.put(GroupDeliveryInfoData.KEY_REASON_CODE, reason.toInt());
    String[] selectionArgs = new String[] {msgId, contact.toString()};

    if (mLocalContentResolver.update(
            GroupDeliveryInfoData.CONTENT_URI,
            values,
            SELECTION_DELIVERY_INFO_BY_MSG_ID_AND_CONTACT,
            selectionArgs)
        < 1) {
      /*
       * No entry updated means that there was no matching row. Adding row and setting
       * delivered timestamp to same as displayed timestamp. This is the most reasonable value
       * we can set at this point.
       */
      addGroupChatDeliveryInfoEntry(
          chatId, contact, msgId, status, reason, timestampDisplayed, timestampDisplayed);
    }
    return true;
  }
  /**
   * Set delivery status for outgoing group chat messages and files. Note that this method should
   * not be used for Status.DELIVERED and Status.DISPLAYED. These states require timestamps and
   * should be set through setGroupChatDeliveryInfoDisplayed and setGroupChatDeliveryInfoDisplayed
   * respectively.
   *
   * @param chatId Group chat ID
   * @param contact The contact ID for which the entry is to be updated
   * @param msgId Message ID
   * @param status Status
   * @param reasonCode Reason code
   * @return true if an entry was updated, otherwise false
   */
  public boolean setGroupChatDeliveryInfoStatusAndReasonCode(
      String chatId, ContactId contact, String msgId, Status status, ReasonCode reasonCode) {
    ContentValues values = new ContentValues();
    values.put(GroupDeliveryInfoData.KEY_STATUS, status.toInt());
    values.put(GroupDeliveryInfoData.KEY_REASON_CODE, reasonCode.toInt());
    String[] selectionArgs = new String[] {msgId, contact.toString()};

    switch (status) {
      case DELIVERED:
      case DISPLAYED:
        throw new IllegalArgumentException(
            "Status that requires "
                + "timestamp passed, use specific method taking timestamp"
                + " to set status "
                + status.toString());
      default:
    }

    return (mLocalContentResolver.update(
            GroupDeliveryInfoData.CONTENT_URI,
            values,
            SELECTION_DELIVERY_INFO_BY_MSG_ID_AND_CONTACT,
            selectionArgs)
        >= 1);
  }
  @Override
  public boolean isDisplayedByAllRecipients(String msgId) {
    Cursor cursor = null;
    try {
      Uri contentUri = Uri.withAppendedPath(GroupDeliveryInfoData.CONTENT_URI, msgId);
      cursor =
          mLocalContentResolver.query(
              contentUri, null, SELECTION_DELIVERY_INFO_NOT_DISPLAYED, null, null);
      CursorUtil.assertCursorIsNotNull(cursor, contentUri);
      return !cursor.moveToFirst();

    } finally {
      CursorUtil.close(cursor);
    }
  }
  @Override
  public boolean isDeliveredToAllRecipients(String msgId) {
    Cursor cursor = null;
    try {
      cursor =
          mLocalContentResolver.query(
              Uri.withAppendedPath(GroupDeliveryInfoData.CONTENT_URI, msgId),
              null,
              SELECTION_CONTACTS_NOT_RECEIVED_MESSAGE,
              null,
              null);
      CursorUtil.assertCursorIsNotNull(cursor, GroupDeliveryInfoData.CONTENT_URI);
      return !cursor.moveToFirst();

    } finally {
      CursorUtil.close(cursor);
    }
  }
 @Override
 public Uri addGroupChatDeliveryInfoEntry(
     String chatId,
     ContactId contact,
     String msgId,
     Status status,
     ReasonCode reasonCode,
     long timestampDelivered,
     long timestampDisplayed) {
   ContentValues values = new ContentValues();
   values.put(GroupDeliveryInfoData.KEY_CHAT_ID, chatId);
   values.put(GroupDeliveryInfoData.KEY_ID, msgId);
   values.put(GroupDeliveryInfoData.KEY_CONTACT, contact.toString());
   values.put(GroupDeliveryInfoData.KEY_STATUS, status.toInt());
   values.put(GroupDeliveryInfoData.KEY_REASON_CODE, reasonCode.toInt());
   values.put(GroupDeliveryInfoData.KEY_TIMESTAMP_DELIVERED, timestampDelivered);
   values.put(GroupDeliveryInfoData.KEY_TIMESTAMP_DISPLAYED, timestampDisplayed);
   return mLocalContentResolver.insert(GroupDeliveryInfoData.CONTENT_URI, values);
 }