private void reveal(View sourceView, int colorRes, final AnimatorListener listener) {
    // Make reveal cover the display
    final RevealView revealView = new RevealView(this);
    revealView.setLayoutParams(mLayoutParams);
    revealView.setRevealColor(getResources().getColor(colorRes));
    mDisplayForeground.addView(revealView);

    final SupportAnimator revealAnimator;
    final int[] clearLocation = new int[2];
    if (sourceView != null) {
      sourceView.getLocationInWindow(clearLocation);
      clearLocation[0] += sourceView.getWidth() / 2;
      clearLocation[1] += sourceView.getHeight() / 2;
    } else {
      clearLocation[0] = mDisplayForeground.getWidth() / 2;
      clearLocation[1] = mDisplayForeground.getHeight() / 2;
    }
    final int revealCenterX = clearLocation[0] - revealView.getLeft();
    final int revealCenterY = clearLocation[1] - revealView.getTop();
    final double x1_2 = Math.pow(revealView.getLeft() - revealCenterX, 2);
    final double x2_2 = Math.pow(revealView.getRight() - revealCenterX, 2);
    final double y_2 = Math.pow(revealView.getTop() - revealCenterY, 2);
    final float revealRadius = (float) Math.max(Math.sqrt(x1_2 + y_2), Math.sqrt(x2_2 + y_2));

    revealAnimator =
        ViewAnimationUtils.createCircularReveal(
            revealView, revealCenterX, revealCenterY, 0.0f, revealRadius);
    revealAnimator.setDuration(getResources().getInteger(android.R.integer.config_longAnimTime));
    revealAnimator.addListener(listener);

    final Animator alphaAnimator = ObjectAnimator.ofFloat(revealView, View.ALPHA, 0.0f);
    alphaAnimator.setDuration(getResources().getInteger(android.R.integer.config_mediumAnimTime));
    alphaAnimator.addListener(
        new AnimationFinishedListener() {
          @Override
          public void onAnimationFinished() {
            mDisplayForeground.removeView(revealView);
          }
        });

    revealAnimator.addListener(
        new AnimationFinishedListener() {
          @Override
          public void onAnimationFinished() {
            play(alphaAnimator);
          }
        });
    play(revealAnimator);
  }
  protected void onResult(final String result) {
    // Calculate the values needed to perform the scale and translation animations,
    // accounting for how the scale will affect the final position of the text.
    final float resultScale =
        mFormulaEditText.getVariableTextSize(result) / mResultEditText.getTextSize();
    final float resultTranslationX =
        (1.0f - resultScale)
            * (mResultEditText.getWidth() / 2.0f - mResultEditText.getPaddingRight());

    // Calculate the height of the formula (without padding)
    final float formulaRealHeight =
        mFormulaEditText.getHeight()
            - mFormulaEditText.getPaddingTop()
            - mFormulaEditText.getPaddingBottom();

    // Calculate the height of the resized result (without padding)
    final float resultRealHeight =
        resultScale
            * (mResultEditText.getHeight()
                - mResultEditText.getPaddingTop()
                - mResultEditText.getPaddingBottom());

    // Now adjust the result upwards!
    final float resultTranslationY =
        // Move the result up (so both formula + result heights match)
        -mFormulaEditText.getHeight()
            // Now switch the result's padding top with the formula's padding top
            - resultScale * mResultEditText.getPaddingTop()
            + mFormulaEditText.getPaddingTop()
            // But the result centers its text! And it's taller now! So adjust for that centered
            // text
            + (formulaRealHeight - resultRealHeight) / 2;

    // Move the formula all the way to the top of the screen
    final float formulaTranslationY = -mFormulaEditText.getBottom();

    // Use a value animator to fade to the final text color over the course of the animation.
    final int resultTextColor = mResultEditText.getCurrentTextColor();
    final int formulaTextColor = mFormulaEditText.getCurrentTextColor();
    final ValueAnimator textColorAnimator =
        ValueAnimator.ofObject(new ArgbEvaluator(), resultTextColor, formulaTextColor);
    textColorAnimator.addUpdateListener(
        new AnimatorUpdateListener() {
          @Override
          public void onAnimationUpdate(ValueAnimator valueAnimator) {
            mResultEditText.setTextColor((Integer) valueAnimator.getAnimatedValue());
          }
        });
    mResultEditText.setText(result);
    mResultEditText.setPivotX(mResultEditText.getWidth() / 2);
    mResultEditText.setPivotY(0f);

    final AnimatorSet animatorSet = new AnimatorSet();
    animatorSet.playTogether(
        textColorAnimator,
        ObjectAnimator.ofFloat(mResultEditText, View.SCALE_X, resultScale),
        ObjectAnimator.ofFloat(mResultEditText, View.SCALE_Y, resultScale),
        ObjectAnimator.ofFloat(mResultEditText, View.TRANSLATION_X, resultTranslationX),
        ObjectAnimator.ofFloat(mResultEditText, View.TRANSLATION_Y, resultTranslationY),
        ObjectAnimator.ofFloat(mFormulaEditText, View.TRANSLATION_Y, formulaTranslationY));
    animatorSet.setDuration(getResources().getInteger(android.R.integer.config_longAnimTime));
    animatorSet.setInterpolator(new AccelerateDecelerateInterpolator());
    animatorSet.addListener(
        new AnimationFinishedListener() {
          @Override
          public void onAnimationFinished() {
            // Reset all of the values modified during the animation.
            mResultEditText.setPivotY(mResultEditText.getHeight() / 2);
            mResultEditText.setTextColor(resultTextColor);
            mResultEditText.setScaleX(1.0f);
            mResultEditText.setScaleY(1.0f);
            mResultEditText.setTranslationX(0.0f);
            mResultEditText.setTranslationY(0.0f);
            mFormulaEditText.setTranslationY(0.0f);

            // Finally update the formula to use the current result.
            mFormulaEditText.setText(result);
            setState(CalculatorState.RESULT);
          }
        });

    play(animatorSet);
  }