docs: public <T> void addValueCallback(
        final KeyPath keyPath, final T property, final LottieValueCallback<T> callback) {
      if (compositionLayer == null) {
        lazyCompositionTasks.add(new LazyCompositionTask() {
          @Override
          public void run(LottieComposition composition) {
            addValueCallback(keyPath, property, callback);
          }
        });
        return;
      }
      boolean invalidate;
      if (keyPath.getResolvedElement() != null) {
        keyPath.getResolvedElement().addValueCallback(property, callback);
        invalidate = true;
      } else {
        List<KeyPath> elements = resolveKeyPath(keyPath);
  
        for (int i = 0; i < elements.size(); i++) {
          //noinspection ConstantConditions
          elements.get(i).getResolvedElement().addValueCallback(property, callback);
        }
        invalidate = !elements.isEmpty();
      }
      if (invalidate) {
        invalidateSelf();
        if (property == LottieProperty.TIME_REMAP) {
          // Time remapping values are read in setProgress. In order for the new value
          // to apply, we have to re-set the progress with the current progress so that the
          // time remapping can be reapplied.
          setProgress(getProgress());
        }
      }
    }