content: package com.actionbarsherlock.internal.nineoldandroids.view.animation;
  
  import java.lang.ref.WeakReference;
  import java.util.WeakHashMap;
  import android.graphics.Matrix;
  import android.graphics.RectF;
  import android.os.Build;
  import android.util.FloatMath;
  import android.view.View;
  import android.view.animation.Animation;
  import android.view.animation.Transformation;
  
  public final class AnimatorProxy extends Animation {
      public static final boolean NEEDS_PROXY = Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB;
  
      private static final WeakHashMap<View, AnimatorProxy> PROXIES =
              new WeakHashMap<View, AnimatorProxy>();
  
      public static AnimatorProxy wrap(View view) {
          AnimatorProxy proxy = PROXIES.get(view);
          if (proxy == null) {
              proxy = new AnimatorProxy(view);
              PROXIES.put(view, proxy);
          }
          return proxy;
      }
  
      private final WeakReference<View> mView;
  
      private float mAlpha = 1;
      private float mScaleX = 1;
      private float mScaleY = 1;
      private float mTranslationX;
      private float mTranslationY;
  
      private final RectF mBefore = new RectF();
      private final RectF mAfter = new RectF();
      private final Matrix mTempMatrix = new Matrix();
  
      private AnimatorProxy(View view) {
          setDuration(0); //perform transformation immediately
          setFillAfter(true); //persist transformation beyond duration
          view.setAnimation(this);
          mView = new WeakReference<View>(view);
      }
  
      public float getAlpha() {
          return mAlpha;
      }
      public void setAlpha(float alpha) {
          if (mAlpha != alpha) {
              mAlpha = alpha;
              View view = mView.get();
              if (view != null) {
                  view.invalidate();
              }
          }
      }
      public float getScaleX() {
          return mScaleX;
      }
      public void setScaleX(float scaleX) {
          if (mScaleX != scaleX) {
              prepareForUpdate();
              mScaleX = scaleX;
              invalidateAfterUpdate();
          }
      }
      public float getScaleY() {
          return mScaleY;
      }
      public void setScaleY(float scaleY) {
          if (mScaleY != scaleY) {
              prepareForUpdate();
              mScaleY = scaleY;
              invalidateAfterUpdate();
          }
      }
      public int getScrollX() {
          View view = mView.get();
          if (view == null) {
              return 0;
          }
          return view.getScrollX();
      }
      public void setScrollX(int value) {
          View view = mView.get();
          if (view != null) {
              view.scrollTo(value, view.getScrollY());
          }
      }
      public int getScrollY() {
          View view = mView.get();
          if (view == null) {
              return 0;
          }
          return view.getScrollY();
      }
      public void setScrollY(int value) {
          View view = mView.get();
          if (view != null) {
              view.scrollTo(view.getScrollY(), value);
          }
      }
  
      public float getTranslationX() {
          return mTranslationX;
      }
      public void setTranslationX(float translationX) {
          if (mTranslationX != translationX) {
              prepareForUpdate();
              mTranslationX = translationX;
              invalidateAfterUpdate();
          }
      }
      public float getTranslationY() {
          return mTranslationY;
      }
      public void setTranslationY(float translationY) {
          if (mTranslationY != translationY) {
              prepareForUpdate();
              mTranslationY = translationY;
              invalidateAfterUpdate();
          }
      }
  
      private void prepareForUpdate() {
          View view = mView.get();
          if (view != null) {
              computeRect(mBefore, view);
          }
      }
      private void invalidateAfterUpdate() {
          View view = mView.get();
          if (view == null) {
              return;
          }
          View parent = (View)view.getParent();
          if (parent == null) {
              return;
          }
  
          view.setAnimation(this);
  
          final RectF after = mAfter;
          computeRect(after, view);
          after.union(mBefore);
  
          parent.invalidate(
                  (int) FloatMath.floor(after.left),
                  (int) FloatMath.floor(after.top),
                  (int) FloatMath.ceil(after.right),
                  (int) FloatMath.ceil(after.bottom));
      }
  
      private void computeRect(final RectF r, View view) {
          // compute current rectangle according to matrix transformation
          final float w = view.getWidth();
          final float h = view.getHeight();
  
          // use a rectangle at 0,0 to make sure we don't run into issues with scaling
          r.set(0, 0, w, h);
  
          final Matrix m = mTempMatrix;
          m.reset();
          transformMatrix(m, view);
          mTempMatrix.mapRect(r);
  
          r.offset(view.getLeft(), view.getTop());
  
          // Straighten coords if rotations flipped them
          if (r.right < r.left) {
              final float f = r.right;
              r.right = r.left;
              r.left = f;
          }
          if (r.bottom < r.top) {
              final float f = r.top;
              r.top = r.bottom;
              r.bottom = f;
          }
      }
  
      private void transformMatrix(Matrix m, View view) {
          final float w = view.getWidth();
          final float h = view.getHeight();
  
          final float sX = mScaleX;
          final float sY = mScaleY;
          if ((sX != 1.0f) || (sY != 1.0f)) {
              final float deltaSX = ((sX * w) - w) / 2f;
              final float deltaSY = ((sY * h) - h) / 2f;
              m.postScale(sX, sY);
              m.postTranslate(-deltaSX, -deltaSY);
          }
          m.postTranslate(mTranslationX, mTranslationY);
      }
  
      @Override
      protected void applyTransformation(float interpolatedTime, Transformation t) {
          View view = mView.get();
          if (view != null) {
              t.setAlpha(mAlpha);
              transformMatrix(t.getMatrix(), view);
          }
      }
  
      @Override
      public void reset() {
          /* Do nothing. */
      }
  }
  