@Override
  public Cursor query(Uri uri, String[] strings, String s, String[] strings1, String s1) {
    // setNotificationUri call aren't really researched

    String limitStr = uri.getQueryParameter("limit");
    int limit = limitStr == null ? Integer.MAX_VALUE : Integer.parseInt(limitStr);

    // we create new matrix cursor and try to fill it
    // projection_all is too far away. better create it over here maybe
    MatrixCursor cursor = new MatrixCursor(Words.PROJECTION_ALL);
    int code = URI_MATCHER.match(uri);
    switch (URI_MATCHER.match(uri)) {
      case WORD:
        String word = uri.getQueryParameter("word");
        // look for position of the word
        if (word != null) {
          int position = Collections.binarySearch(words, word, String.CASE_INSENSITIVE_ORDER);
          if (position >= 0) {
            addWord(cursor, position);
          }
          break;
        }
        String id = uri.getQueryParameter("id");
        if (id != null) {
          int position = Integer.parseInt(id);
          addWord(cursor, position);
          break;
        }
        for (int i = 0; i < words.size() && cursor.getCount() < limit; ++i) {
          addWord(cursor, i);
        }
        cursor.setNotificationUri(getContext().getContentResolver(), Words.CONTENT_URI);
        break;
      case WORD_SUGGESTIONS_FREQUENT:
        // have to think how to implement it
        fillWordSuggestionsFrequent(cursor);
        break;
      case WORD_SUGGESTIONS:
        s = uri.getLastPathSegment();
        if (s.length() < 4) {
          fillWordSuggestionsFrequent(cursor);
          break;
        }

        int start = Collections.binarySearch(words, s, String.CASE_INSENSITIVE_ORDER);
        if (start < 0) {
          start = -(start + 1);
        }
        int i = start;
        while (i < words.size()
            && words.get(i).toLowerCase().startsWith(s)
            && cursor.getCount() < limit) {
          addWord(cursor, i);
          ++i;
        }
        cursor.setNotificationUri(getContext().getContentResolver(), Words.CONTENT_URI);
        break;
      default:
        throw new IllegalArgumentException("Unsupported URI: " + uri);
    }
    return cursor;
  }
 private void copyNotificationUri(MatrixCursor result, Cursor cursor) {
   result.setNotificationUri(getContext().getContentResolver(), cursor.getNotificationUri());
 }
 @Override
 public Cursor query(
     Uri uri, String[] projection, String selection, String[] selectionArgs, String sort) {
   int code = matchURI(uri);
   if (code == MAIL_DETAIL_LIST) {
     uri = getModel().uri();
     Cursor cr = super.query(uri, projection, selection, selectionArgs, sort);
     OModel model = getModel();
     MatrixCursor parents = new MatrixCursor(cr.getColumnNames());
     MatrixCursor childs = new MatrixCursor(cr.getColumnNames());
     if (cr.moveToFirst()) {
       do {
         int parent_id = cr.getInt(cr.getColumnIndex("parent_id"));
         if (parent_id == 0) {
           // add to parent
           List<Object> values = new ArrayList<Object>();
           for (String col : cr.getColumnNames()) {
             OColumn c = new OColumn("");
             c.setName(col);
             values.add(model.createRecordRow(c, cr));
           }
           parents.addRow(values.toArray(new Object[values.size()]));
         } else {
           // add to child
           List<Object> values = new ArrayList<Object>();
           for (String col : cr.getColumnNames()) {
             OColumn c = new OColumn("");
             c.setName(col);
             values.add(model.createRecordRow(c, cr));
           }
           childs.addRow(values.toArray(new Object[values.size()]));
         }
       } while (cr.moveToNext());
       MergeCursor mergedData = new MergeCursor(new Cursor[] {parents, childs});
       return mergedData;
     }
     parents.close();
     childs.close();
   }
   if (code == MAIL_INBOX) {
     uri = getModel().uri();
     Cursor cr = super.query(uri, projection, selection, selectionArgs, sort);
     List<String> parent_list = new ArrayList<String>();
     OModel model = getModel();
     MatrixCursor newCr = null;
     if (cr.moveToFirst()) {
       newCr = new MatrixCursor(cr.getColumnNames());
       do {
         List<Object> values = new ArrayList<Object>();
         int parent_id = cr.getInt(cr.getColumnIndex("parent_id"));
         int _id = cr.getInt(cr.getColumnIndex(OColumn.ROW_ID));
         if (parent_id != 0 && !parent_list.contains("parent_" + parent_id)) {
           // Child found Creating parent row...
           List<ODataRow> parent_row =
               model
                   .browse()
                   .columns(projection)
                   .addWhere(OColumn.ROW_ID, "=", parent_id)
                   .fetch(false);
           for (String col : cr.getColumnNames()) {
             if (parent_row.size() > 0 && parent_row.get(0).contains(col)) {
               ODataRow row = parent_row.get(0);
               if (col.equals("short_body")) {
                 values.add(cr.getString(cr.getColumnIndex("short_body")));
               } else if (col.equals("date")) {
                 values.add(cr.getString(cr.getColumnIndex("date")));
               } else if (col.equals("to_read")) {
                 values.add(cr.getString(cr.getColumnIndex("to_read")));
               } else {
                 values.add(row.get(col));
               }
             } else {
               OColumn c = new OColumn("");
               c.setName(col);
               values.add(model.createRecordRow(c, cr));
             }
           }
           newCr.addRow(values.toArray(new Object[values.size()]));
           parent_list.add("parent_" + parent_id);
         } else {
           if (!parent_list.contains("parent_" + _id) && parent_id == 0) {
             // Its parent. adding row
             for (String col : newCr.getColumnNames()) {
               OColumn c = new OColumn("");
               c.setName(col);
               values.add(model.createRecordRow(c, cr));
             }
             parent_list.add("parent_" + _id);
             newCr.addRow(values.toArray(new Object[values.size()]));
           }
         }
       } while (cr.moveToNext());
       Context ctx = getContext();
       assert ctx != null;
       newCr.setNotificationUri(ctx.getContentResolver(), uri);
       return newCr;
     }
   }
   return super.query(uri, projection, selection, selectionArgs, sort);
 }