@Override
  public Uri insert(Uri uri, ContentValues values) {
    // Find matching path.
    final int match = sUriMatcher.match(uri);

    // Avoid the expensive string concatenation below if not loggable
    if (BuildConfig.DEBUG) {
      Log.v(TAG, "insert(uri=" + uri + ", values=" + values.toString() + ")");
    }

    // Get the database and run the insert
    SQLiteDatabase db = mOpenHelper.getWritableDatabase();
    switch (match) {
      case PAYMENTS:
        {
          db.insertOrThrow(AppDatabase.Tables.PAYMENTS, null, values);
          getContext().getContentResolver().notifyChange(uri, null);
          // Generate Uri with remote id.
          return AppContract.Payments.buildUri(values.getAsString(AppContract.Payments.ID));
        }
      default:
        {
          throw new UnsupportedOperationException("Unknown insert uri: " + uri);
        }
    }
  }
  @Override
  public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
    // Find matching path.
    final int match = sUriMatcher.match(uri);

    // Avoid the expensive string concatenation below if not loggable
    if (BuildConfig.DEBUG) {
      Log.v(TAG, "update(uri=" + uri + ", values=" + values.toString() + ")");
    }

    // Create a selection builder from Uri.
    final SelectionBuilder builder = buildSimpleSelection(uri, match);

    // Get the database and run the update
    SQLiteDatabase db = mOpenHelper.getWritableDatabase();
    int count = builder.where(selection, selectionArgs).update(db, values);
    getContext().getContentResolver().notifyChange(uri, null);
    return count;
  }
 /** Transactional implementation of applyBatch. */
 @Override
 public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> operations)
     throws OperationApplicationException {
   ContentProviderResult[] result = new ContentProviderResult[operations.size()];
   // Opens the database object in "write" mode.
   SQLiteDatabase db = mOpenHelper.getWritableDatabase();
   // Begin a transaction
   db.beginTransaction();
   try {
     int i = 0;
     for (ContentProviderOperation operation : operations) {
       // Chain the result for back references
       result[i++] = operation.apply(this, result, i);
     }
     db.setTransactionSuccessful();
   } finally {
     db.endTransaction();
   }
   return result;
 }
  @Override
  public Cursor query(
      Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
    // Find matching path.
    final int match = sUriMatcher.match(uri);

    // Avoid the expensive string concatenation below if not loggable
    if (BuildConfig.DEBUG) {
      Log.v(
          TAG,
          "uri="
              + uri
              + " match="
              + match
              + " proj="
              + Arrays.toString(projection)
              + " selection="
              + selection
              + " args="
              + Arrays.toString(selectionArgs)
              + ")");
    }

    // Create a selection builder from Uri.
    final SelectionBuilder builder = buildExpandedSelection(uri, match);

    // Get the database and run the query
    SQLiteDatabase db = mOpenHelper.getReadableDatabase();
    Cursor cursor = builder.where(selection, selectionArgs).query(db, projection, sortOrder);
    // Tell the cursor what uri to watch, so it knows when its source
    // data changes
    Context context = getContext();
    if (null != context) {
      cursor.setNotificationUri(context.getContentResolver(), uri);
    }
    return cursor;
  }