code: @SuppressWarnings("BooleanMethodIsAlwaysInverted")
      public boolean canDeleteSelection(int beforeLength) {
          if (getObjects().size() < 1) return true;
  
          // if beforeLength is 1, we either have no selection or the call is coming from OnKey Event.
          // In these scenarios, getSelectionStart() will return the correct value.
  
          int endSelection = getSelectionEnd();
          int startSelection = beforeLength == 1 ? getSelectionStart() : endSelection - beforeLength;
  
          Editable text = getText();
          TokenImageSpan[] spans = text.getSpans(0, text.length(), TokenImageSpan.class);
  
          // Iterate over all tokens and allow the deletion
          // if there are no tokens not removable in the selection
          for (TokenImageSpan span : spans) {
              int startTokenSelection = text.getSpanStart(span);
              int endTokenSelection = text.getSpanEnd(span);
  
              // moving on, no need to check this token
              if (isTokenRemovable(span.token)) continue;
  
              if (startSelection == endSelection) {
                  // Delete single
                  if (endTokenSelection + 1 == endSelection) {
                      return false;
                  }
              } else {
                  // Delete range
                  // Don't delete if a non removable token is in range
                  if (startSelection <= startTokenSelection
                          && endTokenSelection + 1 <= endSelection) {
                      return false;
                  }
              }
          }
          return true;
      }
docs: Checks if selection can be deleted. This method is called from TokenInputConnection .
  @param beforeLength the number of characters before the current selection end to check
  @return true if there are no non-deletable pieces of the section