private void includeDefaultDocument(MatrixCursor result) {
   final RowBuilder row = result.newRow();
   row.add(Document.COLUMN_DOCUMENT_ID, DOC_ID_ROOT);
   row.add(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR);
   row.add(
       Document.COLUMN_FLAGS,
       Document.FLAG_DIR_PREFERS_LAST_MODIFIED | Document.FLAG_DIR_SUPPORTS_CREATE);
 }
 @Override
 public Cursor queryRoots(String[] projection) throws FileNotFoundException {
   final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection));
   synchronized (mRootsLock) {
     for (RootInfo root : mRoots.values()) {
       final RowBuilder row = result.newRow();
       row.add(Root.COLUMN_ROOT_ID, root.rootId);
       row.add(Root.COLUMN_FLAGS, root.flags);
       row.add(Root.COLUMN_TITLE, root.title);
       row.add(Root.COLUMN_DOCUMENT_ID, root.docId);
       row.add(Root.COLUMN_AVAILABLE_BYTES, root.path.getFreeSpace());
     }
   }
   return result;
 }
 @Override
 public Cursor queryRoots(String[] projection) throws FileNotFoundException {
   final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection));
   final RowBuilder row = result.newRow();
   row.add(Root.COLUMN_ROOT_ID, DOC_ID_ROOT);
   row.add(
       Root.COLUMN_FLAGS,
       Root.FLAG_LOCAL_ONLY | Root.FLAG_SUPPORTS_RECENTS | Root.FLAG_SUPPORTS_CREATE);
   row.add(Root.COLUMN_ICON, R.mipmap.ic_launcher_download);
   row.add(Root.COLUMN_TITLE, getContext().getString(R.string.root_downloads));
   row.add(Root.COLUMN_DOCUMENT_ID, DOC_ID_ROOT);
   return result;
 }
  private void includeFile(MatrixCursor result, String docId, File file)
      throws FileNotFoundException {
    if (docId == null) {
      docId = getDocIdForFile(file);
    } else {
      file = getFileForDocId(docId);
    }

    int flags = 0;

    if (file.canWrite()) {
      if (file.isDirectory()) {
        flags |= Document.FLAG_DIR_SUPPORTS_CREATE;
        flags |= Document.FLAG_SUPPORTS_DELETE;
        flags |= Document.FLAG_SUPPORTS_RENAME;
      } else {
        flags |= Document.FLAG_SUPPORTS_WRITE;
        flags |= Document.FLAG_SUPPORTS_DELETE;
        flags |= Document.FLAG_SUPPORTS_RENAME;
      }
    }

    final String displayName = file.getName();
    final String mimeType = getTypeForFile(file);
    if (mimeType.startsWith("image/")) {
      flags |= Document.FLAG_SUPPORTS_THUMBNAIL;
    }

    final RowBuilder row = result.newRow();
    row.add(Document.COLUMN_DOCUMENT_ID, docId);
    row.add(Document.COLUMN_DISPLAY_NAME, displayName);
    row.add(Document.COLUMN_SIZE, file.length());
    row.add(Document.COLUMN_MIME_TYPE, mimeType);
    row.add(Document.COLUMN_FLAGS, flags);

    // Only publish dates reasonably after epoch
    long lastModified = file.lastModified();
    if (lastModified > 31536000000L) {
      row.add(Document.COLUMN_LAST_MODIFIED, lastModified);
    }
  }
  private void includeTransferFromCursor(MatrixCursor result, Cursor cursor) {
    final long id = cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_ID));
    final String docId = String.valueOf(id);

    final String displayName =
        cursor.getString(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_TITLE));
    String summary =
        cursor.getString(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_DESCRIPTION));
    String mimeType =
        cursor.getString(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_MEDIA_TYPE));
    if (mimeType == null) {
      // Provide fake MIME type so it's openable
      mimeType = "vnd.android.document/file";
    }
    Long size =
        cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
    if (size == -1) {
      size = null;
    }

    final int status = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_STATUS));
    switch (status) {
      case DownloadManager.STATUS_SUCCESSFUL:
        break;
      case DownloadManager.STATUS_PAUSED:
        summary = getContext().getString(R.string.download_queued);
        break;
      case DownloadManager.STATUS_PENDING:
        summary = getContext().getString(R.string.download_queued);
        break;
      case DownloadManager.STATUS_RUNNING:
        final long progress =
            cursor.getLong(
                cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
        if (size != null) {
          final long percent = progress * 100 / size;
          summary = getContext().getString(R.string.download_running_percent, percent);
        } else {
          summary = getContext().getString(R.string.download_running);
        }
        break;
      case DownloadManager.STATUS_FAILED:
      default:
        summary = getContext().getString(R.string.download_error);
        break;
    }

    int flags = Document.FLAG_SUPPORTS_DELETE | Document.FLAG_SUPPORTS_WRITE;
    if (mimeType != null && mimeType.startsWith("image/")) {
      flags |= Document.FLAG_SUPPORTS_THUMBNAIL;
    }

    final long lastModified =
        cursor.getLong(
            cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_LAST_MODIFIED_TIMESTAMP));

    final RowBuilder row = result.newRow();
    row.add(Document.COLUMN_DOCUMENT_ID, docId);
    row.add(Document.COLUMN_DISPLAY_NAME, displayName);
    row.add(Document.COLUMN_SUMMARY, summary);
    row.add(Document.COLUMN_SIZE, size);
    row.add(Document.COLUMN_MIME_TYPE, mimeType);
    row.add(Document.COLUMN_LAST_MODIFIED, lastModified);
    row.add(Document.COLUMN_FLAGS, flags);
  }
  @Override
  public Cursor searchContact(Context ctxt, CharSequence constraint) {
    String phone = "";
    String cons = "";

    if (constraint != null) {
      cons = constraint.toString();

      if (usefulAsDigits(cons)) {
        phone = PhoneNumberUtils.convertKeypadLettersToDigits(cons);
        if (phone.equals(cons)) {
          phone = "";
        } else {
          phone = phone.trim();
        }
      }
    }

    Uri uri = Uri.withAppendedPath(Contacts.Phones.CONTENT_URI, "");
    /*
     * if we decide to filter based on phone types use a selection
     * like this.
    String selection = String.format("%s=%s OR %s=%s OR %s=%s",
            Phone.TYPE,
            Phone.TYPE_MOBILE,
            Phone.TYPE,
            Phone.TYPE_WORK_MOBILE,
            Phone.TYPE,
            Phone.TYPE_MMS);
     */
    String selection =
        String.format(
            "%s LIKE ? OR %s LIKE ?", Contacts.Phones.NUMBER, Contacts.Phones.DISPLAY_NAME);
    Cursor phoneCursor =
        ctxt.getContentResolver()
            .query(
                uri,
                PROJECTION_PHONE,
                selection,
                new String[] {cons + "%", "%" + cons + "%"},
                SORT_ORDER);

    if (phone.length() > 0) {

      MatrixCursor translated = new MatrixCursor(PROJECTION_PHONE, 1 /*2*/);

      RowBuilder result = translated.newRow();
      result.add(Integer.valueOf(-1)); // ID
      result.add(Long.valueOf(-1)); // CONTACT_ID
      result.add(Integer.valueOf(Contacts.Phones.TYPE_CUSTOM)); // TYPE
      result.add(cons); // NUMBER

      result.add("\u00A0"); // LABEL
      result.add(cons); // NAME

      // Rewriten as phone number
      /*
               result = translated.newRow();
               result.add(Integer.valueOf(-1));                    // ID
               result.add(Long.valueOf(-1));                       // CONTACT_ID
               result.add(Integer.valueOf(ContactsContract.CommonDataKinds.Phone.TYPE_CUSTOM));     // TYPE
               result.add(phone);                                  // NUMBER
      */
      /*
       * The "\u00A0" keeps Phone.getDisplayLabel() from deciding
       * to display the default label ("Home") next to the transformation
       * of the letters into numbers.
       */
      /*
               result.add("\u00A0");                               // LABEL
               result.add(cons);                                   // NAME
      */

      return new MergeCursor(new Cursor[] {translated, phoneCursor});
    } else {
      return phoneCursor;
    }
  }