code: private void animatePropertyBy(int constantName, float startValue, float byValue) {
          // First, cancel any existing animations on this property
          if (mAnimatorMap.size() > 0) {
              Animator animatorToCancel = null;
              Set<Animator> animatorSet = mAnimatorMap.keySet();
              for (Animator runningAnim : animatorSet) {
                  PropertyBundle bundle = mAnimatorMap.get(runningAnim);
                  if (bundle.cancel(constantName)) {
                      // property was canceled - cancel the animation if it's now empty
                      // Note that it's safe to break out here because every new animation
                      // on a property will cancel a previous animation on that property, so
                      // there can only ever be one such animation running.
                      if (bundle.mPropertyMask == NONE) {
                          // the animation is no longer changing anything - cancel it
                          animatorToCancel = runningAnim;
                          break;
                      }
                  }
              }
              if (animatorToCancel != null) {
                  animatorToCancel.cancel();
              }
          }
  
          NameValuesHolder nameValuePair = new NameValuesHolder(constantName, startValue, byValue);
          mPendingAnimations.add(nameValuePair);
          View v = mView.get();
          if (v != null) {
              v.removeCallbacks(mAnimationStarter);
              v.post(mAnimationStarter);
          }
      }
docs: Utility function, called by animateProperty() and animatePropertyBy(), which handles the
  details of adding a pending animation and posting the request to start the animation.
  
  @param constantName The specifier for the property being animated
  @param startValue The starting value of the property
  @param byValue The amount by which the property will change