| Index: content/public/android/java/src/org/chromium/content/browser/PopupZoomer.java
|
| diff --git a/content/public/android/java/src/org/chromium/content/browser/PopupZoomer.java b/content/public/android/java/src/org/chromium/content/browser/PopupZoomer.java
|
| deleted file mode 100644
|
| index bdc54301f220634ee7b909287a4de79908ca697d..0000000000000000000000000000000000000000
|
| --- a/content/public/android/java/src/org/chromium/content/browser/PopupZoomer.java
|
| +++ /dev/null
|
| @@ -1,555 +0,0 @@
|
| -// Copyright 2012 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -package org.chromium.content.browser;
|
| -
|
| -import android.content.Context;
|
| -import android.content.res.Resources;
|
| -import android.graphics.Bitmap;
|
| -import android.graphics.Canvas;
|
| -import android.graphics.Color;
|
| -import android.graphics.Paint;
|
| -import android.graphics.Path;
|
| -import android.graphics.Path.Direction;
|
| -import android.graphics.PointF;
|
| -import android.graphics.PorterDuff.Mode;
|
| -import android.graphics.PorterDuffXfermode;
|
| -import android.graphics.Rect;
|
| -import android.graphics.RectF;
|
| -import android.graphics.Region.Op;
|
| -import android.graphics.drawable.ColorDrawable;
|
| -import android.graphics.drawable.Drawable;
|
| -import android.os.SystemClock;
|
| -import android.util.Log;
|
| -import android.view.GestureDetector;
|
| -import android.view.MotionEvent;
|
| -import android.view.View;
|
| -import android.view.animation.Interpolator;
|
| -import android.view.animation.OvershootInterpolator;
|
| -
|
| -import org.chromium.content.R;
|
| -
|
| -/**
|
| - * PopupZoomer is used to show the on-demand link zooming popup. It handles manipulation of the
|
| - * canvas and touch events to display the on-demand zoom magnifier.
|
| - */
|
| -class PopupZoomer extends View {
|
| - private static final String LOGTAG = "PopupZoomer";
|
| -
|
| - // The padding between the edges of the view and the popup. Note that there is a mirror
|
| - // constant in content/renderer/render_view_impl.cc which should be kept in sync if
|
| - // this is changed.
|
| - private static final int ZOOM_BOUNDS_MARGIN = 25;
|
| - // Time it takes for the animation to finish in ms.
|
| - private static final long ANIMATION_DURATION = 300;
|
| -
|
| - /**
|
| - * Interface to be implemented to listen for touch events inside the zoomed area.
|
| - * The MotionEvent coordinates correspond to original unzoomed view.
|
| - */
|
| - public static interface OnTapListener {
|
| - public boolean onSingleTap(View v, MotionEvent event);
|
| - public boolean onLongPress(View v, MotionEvent event);
|
| - }
|
| -
|
| - private OnTapListener mOnTapListener = null;
|
| -
|
| - /**
|
| - * Interface to be implemented to add and remove PopupZoomer to/from the view hierarchy.
|
| - */
|
| - public static interface OnVisibilityChangedListener {
|
| - public void onPopupZoomerShown(PopupZoomer zoomer);
|
| - public void onPopupZoomerHidden(PopupZoomer zoomer);
|
| - }
|
| -
|
| - private OnVisibilityChangedListener mOnVisibilityChangedListener = null;
|
| -
|
| - // Cached drawable used to frame the zooming popup.
|
| - // TODO(tonyg): This should be marked purgeable so that if the system wants to recover this
|
| - // memory, we can just reload it from the resource ID next time it is needed.
|
| - // See android.graphics.BitmapFactory.Options#inPurgeable
|
| - private static Drawable sOverlayDrawable;
|
| - // The padding used for drawing the overlay around the content, instead of directly above it.
|
| - private static Rect sOverlayPadding;
|
| - // The radius of the overlay bubble, used for rounding the bitmap to draw underneath it.
|
| - private static float sOverlayCornerRadius;
|
| -
|
| - private final Interpolator mShowInterpolator = new OvershootInterpolator();
|
| - private final Interpolator mHideInterpolator = new ReverseInterpolator(mShowInterpolator);
|
| -
|
| - private boolean mAnimating = false;
|
| - private boolean mShowing = false;
|
| - private long mAnimationStartTime = 0;
|
| -
|
| - // The time that was left for the outwards animation to finish.
|
| - // This is used in the case that the zoomer is cancelled while it is still animating outwards,
|
| - // to avoid having it jump to full size then animate closed.
|
| - private long mTimeLeft = 0;
|
| -
|
| - // initDimensions() needs to be called in onDraw().
|
| - private boolean mNeedsToInitDimensions;
|
| -
|
| - // Available view area after accounting for ZOOM_BOUNDS_MARGIN.
|
| - private RectF mViewClipRect;
|
| -
|
| - // The target rect to be zoomed.
|
| - private Rect mTargetBounds;
|
| -
|
| - // The bitmap to hold the zoomed view.
|
| - private Bitmap mZoomedBitmap;
|
| -
|
| - // How far to shift the canvas after all zooming is done, to keep it inside the bounds of the
|
| - // view (including margin).
|
| - private float mShiftX = 0, mShiftY = 0;
|
| - // The magnification factor of the popup. It is recomputed once we have mTargetBounds and
|
| - // mZoomedBitmap.
|
| - private float mScale = 1.0f;
|
| - // The bounds representing the actual zoomed popup.
|
| - private RectF mClipRect;
|
| - // The extrusion values are how far the zoomed area (mClipRect) extends from the touch point.
|
| - // These values to used to animate the popup.
|
| - private float mLeftExtrusion, mTopExtrusion, mRightExtrusion, mBottomExtrusion;
|
| - // The last touch point, where the animation will start from.
|
| - private final PointF mTouch = new PointF();
|
| -
|
| - // Since we sometimes overflow the bounds of the mViewClipRect, we need to allow scrolling.
|
| - // Current scroll position.
|
| - private float mPopupScrollX, mPopupScrollY;
|
| - // Scroll bounds.
|
| - private float mMinScrollX, mMaxScrollX;
|
| - private float mMinScrollY, mMaxScrollY;
|
| -
|
| - private GestureDetector mGestureDetector;
|
| -
|
| - private static float getOverlayCornerRadius(Context context) {
|
| - if (sOverlayCornerRadius == 0) {
|
| - try {
|
| - sOverlayCornerRadius = context.getResources().getDimension(
|
| - R.dimen.link_preview_overlay_radius);
|
| - } catch (Resources.NotFoundException e) {
|
| - Log.w(LOGTAG, "No corner radius resource for PopupZoomer overlay found.");
|
| - sOverlayCornerRadius = 1.0f;
|
| - }
|
| - }
|
| - return sOverlayCornerRadius;
|
| - }
|
| -
|
| - /**
|
| - * Gets the drawable that should be used to frame the zooming popup, loading
|
| - * it from the resource bundle if not already cached.
|
| - */
|
| - private static Drawable getOverlayDrawable(Context context) {
|
| - if (sOverlayDrawable == null) {
|
| - try {
|
| - sOverlayDrawable = context.getResources().getDrawable(
|
| - R.drawable.ondemand_overlay);
|
| - } catch (Resources.NotFoundException e) {
|
| - Log.w(LOGTAG, "No drawable resource for PopupZoomer overlay found.");
|
| - sOverlayDrawable = new ColorDrawable();
|
| - }
|
| - sOverlayPadding = new Rect();
|
| - sOverlayDrawable.getPadding(sOverlayPadding);
|
| - }
|
| - return sOverlayDrawable;
|
| - }
|
| -
|
| - private static float constrain(float amount, float low, float high) {
|
| - return amount < low ? low : (amount > high ? high : amount);
|
| - }
|
| -
|
| - private static int constrain(int amount, int low, int high) {
|
| - return amount < low ? low : (amount > high ? high : amount);
|
| - }
|
| -
|
| - /**
|
| - * Creates Popupzoomer.
|
| - * @param context Context to be used.
|
| - * @param overlayRadiusDimensoinResId Resource to be used to get overlay corner radius.
|
| - */
|
| - public PopupZoomer(Context context) {
|
| - super(context);
|
| -
|
| - setVisibility(INVISIBLE);
|
| - setFocusable(true);
|
| - setFocusableInTouchMode(true);
|
| -
|
| - GestureDetector.SimpleOnGestureListener listener =
|
| - new GestureDetector.SimpleOnGestureListener() {
|
| - @Override
|
| - public boolean onScroll(MotionEvent e1, MotionEvent e2,
|
| - float distanceX, float distanceY) {
|
| - if (mAnimating) return true;
|
| -
|
| - if (isTouchOutsideArea(e1.getX(), e1.getY())) {
|
| - hide(true);
|
| - } else {
|
| - scroll(distanceX, distanceY);
|
| - }
|
| - return true;
|
| - }
|
| -
|
| - @Override
|
| - public boolean onSingleTapUp(MotionEvent e) {
|
| - return handleTapOrPress(e, false);
|
| - }
|
| -
|
| - @Override
|
| - public void onLongPress(MotionEvent e) {
|
| - handleTapOrPress(e, true);
|
| - }
|
| -
|
| - private boolean handleTapOrPress(MotionEvent e, boolean isLongPress) {
|
| - if (mAnimating) return true;
|
| -
|
| - float x = e.getX();
|
| - float y = e.getY();
|
| - if (isTouchOutsideArea(x, y)) {
|
| - // User clicked on area outside the popup.
|
| - hide(true);
|
| - } else if (mOnTapListener != null) {
|
| - PointF converted = convertTouchPoint(x, y);
|
| - MotionEvent event = MotionEvent.obtainNoHistory(e);
|
| - event.setLocation(converted.x, converted.y);
|
| - if (isLongPress) {
|
| - mOnTapListener.onLongPress(PopupZoomer.this, event);
|
| - } else {
|
| - mOnTapListener.onSingleTap(PopupZoomer.this, event);
|
| - }
|
| - hide(true);
|
| - }
|
| - return true;
|
| - }
|
| - };
|
| - mGestureDetector = new GestureDetector(context, listener);
|
| - }
|
| -
|
| - /**
|
| - * Sets the OnTapListener.
|
| - */
|
| - public void setOnTapListener(OnTapListener listener) {
|
| - mOnTapListener = listener;
|
| - }
|
| -
|
| - /**
|
| - * Sets the OnVisibilityChangedListener.
|
| - */
|
| - public void setOnVisibilityChangedListener(OnVisibilityChangedListener listener) {
|
| - mOnVisibilityChangedListener = listener;
|
| - }
|
| -
|
| - /**
|
| - * Sets the bitmap to be used for the zoomed view.
|
| - */
|
| - public void setBitmap(Bitmap bitmap) {
|
| - if (mZoomedBitmap != null) {
|
| - mZoomedBitmap.recycle();
|
| - mZoomedBitmap = null;
|
| - }
|
| - mZoomedBitmap = bitmap;
|
| -
|
| - // Round the corners of the bitmap so it doesn't stick out around the overlay.
|
| - Canvas canvas = new Canvas(mZoomedBitmap);
|
| - Path path = new Path();
|
| - RectF canvasRect = new RectF(0, 0, canvas.getWidth(), canvas.getHeight());
|
| - float overlayCornerRadius = getOverlayCornerRadius(getContext());
|
| - path.addRoundRect(canvasRect, overlayCornerRadius, overlayCornerRadius, Direction.CCW);
|
| - canvas.clipPath(path, Op.XOR);
|
| - Paint clearPaint = new Paint();
|
| - clearPaint.setXfermode(new PorterDuffXfermode(Mode.SRC));
|
| - clearPaint.setColor(Color.TRANSPARENT);
|
| - canvas.drawPaint(clearPaint);
|
| - }
|
| -
|
| - private void scroll(float x, float y) {
|
| - mPopupScrollX = constrain(mPopupScrollX - x, mMinScrollX, mMaxScrollX);
|
| - mPopupScrollY = constrain(mPopupScrollY - y, mMinScrollY, mMaxScrollY);
|
| - invalidate();
|
| - }
|
| -
|
| - private void startAnimation(boolean show) {
|
| - mAnimating = true;
|
| - mShowing = show;
|
| - mTimeLeft = 0;
|
| - if (show) {
|
| - setVisibility(VISIBLE);
|
| - mNeedsToInitDimensions = true;
|
| - if (mOnVisibilityChangedListener != null) {
|
| - mOnVisibilityChangedListener.onPopupZoomerShown(this);
|
| - }
|
| - } else {
|
| - long endTime = mAnimationStartTime + ANIMATION_DURATION;
|
| - mTimeLeft = endTime - SystemClock.uptimeMillis();
|
| - if (mTimeLeft < 0) mTimeLeft = 0;
|
| - }
|
| - mAnimationStartTime = SystemClock.uptimeMillis();
|
| - invalidate();
|
| - }
|
| -
|
| - private void hideImmediately() {
|
| - mAnimating = false;
|
| - mShowing = false;
|
| - mTimeLeft = 0;
|
| - if (mOnVisibilityChangedListener != null) {
|
| - mOnVisibilityChangedListener.onPopupZoomerHidden(this);
|
| - }
|
| - setVisibility(INVISIBLE);
|
| - mZoomedBitmap.recycle();
|
| - mZoomedBitmap = null;
|
| - }
|
| -
|
| - /**
|
| - * Returns true if the view is currently being shown (or is animating).
|
| - */
|
| - public boolean isShowing() {
|
| - return mShowing || mAnimating;
|
| - }
|
| -
|
| - /**
|
| - * Sets the last touch point (on the unzoomed view).
|
| - */
|
| - public void setLastTouch(float x, float y) {
|
| - mTouch.x = x;
|
| - mTouch.y = y;
|
| - }
|
| -
|
| - private void setTargetBounds(Rect rect) {
|
| - mTargetBounds = rect;
|
| - }
|
| -
|
| - private void initDimensions() {
|
| - if (mTargetBounds == null || mTouch == null) return;
|
| -
|
| - // Compute the final zoom scale.
|
| - mScale = (float) mZoomedBitmap.getWidth() / mTargetBounds.width();
|
| -
|
| - float l = mTouch.x - mScale * (mTouch.x - mTargetBounds.left);
|
| - float t = mTouch.y - mScale * (mTouch.y - mTargetBounds.top);
|
| - float r = l + mZoomedBitmap.getWidth();
|
| - float b = t + mZoomedBitmap.getHeight();
|
| - mClipRect = new RectF(l, t, r, b);
|
| - int width = getWidth();
|
| - int height = getHeight();
|
| -
|
| - mViewClipRect = new RectF(ZOOM_BOUNDS_MARGIN,
|
| - ZOOM_BOUNDS_MARGIN,
|
| - width - ZOOM_BOUNDS_MARGIN,
|
| - height - ZOOM_BOUNDS_MARGIN);
|
| -
|
| - // Ensure it stays inside the bounds of the view. First shift it around to see if it
|
| - // can fully fit in the view, then clip it to the padding section of the view to
|
| - // ensure no overflow.
|
| - mShiftX = 0;
|
| - mShiftY = 0;
|
| -
|
| - // Right now this has the happy coincidence of showing the leftmost portion
|
| - // of a scaled up bitmap, which usually has the text in it. When we want to support
|
| - // RTL languages, we can conditionally switch the order of this check to push it
|
| - // to the left instead of right.
|
| - if (mClipRect.left < ZOOM_BOUNDS_MARGIN) {
|
| - mShiftX = ZOOM_BOUNDS_MARGIN - mClipRect.left;
|
| - mClipRect.left += mShiftX;
|
| - mClipRect.right += mShiftX;
|
| - } else if (mClipRect.right > width - ZOOM_BOUNDS_MARGIN) {
|
| - mShiftX = (width - ZOOM_BOUNDS_MARGIN - mClipRect.right);
|
| - mClipRect.right += mShiftX;
|
| - mClipRect.left += mShiftX;
|
| - }
|
| - if (mClipRect.top < ZOOM_BOUNDS_MARGIN) {
|
| - mShiftY = ZOOM_BOUNDS_MARGIN - mClipRect.top;
|
| - mClipRect.top += mShiftY;
|
| - mClipRect.bottom += mShiftY;
|
| - } else if (mClipRect.bottom > height - ZOOM_BOUNDS_MARGIN) {
|
| - mShiftY = height - ZOOM_BOUNDS_MARGIN - mClipRect.bottom;
|
| - mClipRect.bottom += mShiftY;
|
| - mClipRect.top += mShiftY;
|
| - }
|
| -
|
| - // Allow enough scrolling to get to the entire bitmap that may be clipped inside the
|
| - // bounds of the view.
|
| - mMinScrollX = mMaxScrollX = mMinScrollY = mMaxScrollY = 0;
|
| - if (mViewClipRect.right + mShiftX < mClipRect.right) {
|
| - mMinScrollX = mViewClipRect.right - mClipRect.right;
|
| - }
|
| - if (mViewClipRect.left + mShiftX > mClipRect.left) {
|
| - mMaxScrollX = mViewClipRect.left - mClipRect.left;
|
| - }
|
| - if (mViewClipRect.top + mShiftY > mClipRect.top) {
|
| - mMaxScrollY = mViewClipRect.top - mClipRect.top;
|
| - }
|
| - if (mViewClipRect.bottom + mShiftY < mClipRect.bottom) {
|
| - mMinScrollY = mViewClipRect.bottom - mClipRect.bottom;
|
| - }
|
| - // Now that we know how much we need to scroll, we can intersect with mViewClipRect.
|
| - mClipRect.intersect(mViewClipRect);
|
| -
|
| - mLeftExtrusion = mTouch.x - mClipRect.left;
|
| - mRightExtrusion = mClipRect.right - mTouch.x;
|
| - mTopExtrusion = mTouch.y - mClipRect.top;
|
| - mBottomExtrusion = mClipRect.bottom - mTouch.y;
|
| -
|
| - // Set an initial scroll position to take touch point into account.
|
| - float percentX =
|
| - (mTouch.x - mTargetBounds.centerX()) / (mTargetBounds.width() / 2.f) + .5f;
|
| - float percentY =
|
| - (mTouch.y - mTargetBounds.centerY()) / (mTargetBounds.height() / 2.f) + .5f;
|
| -
|
| - float scrollWidth = mMaxScrollX - mMinScrollX;
|
| - float scrollHeight = mMaxScrollY - mMinScrollY;
|
| - mPopupScrollX = scrollWidth * percentX * -1f;
|
| - mPopupScrollY = scrollHeight * percentY * -1f;
|
| - // Constrain initial scroll position within allowed bounds.
|
| - mPopupScrollX = constrain(mPopupScrollX, mMinScrollX, mMaxScrollX);
|
| - mPopupScrollY = constrain(mPopupScrollY, mMinScrollY, mMaxScrollY);
|
| - }
|
| -
|
| - /*
|
| - * Tests override it as the PopupZoomer is never attached to the view hierarchy.
|
| - */
|
| - protected boolean acceptZeroSizeView() {
|
| - return false;
|
| - }
|
| -
|
| - @Override
|
| - protected void onDraw(Canvas canvas) {
|
| - if (!isShowing() || mZoomedBitmap == null) return;
|
| - if (!acceptZeroSizeView() && (getWidth() == 0 || getHeight() == 0)) return;
|
| -
|
| - if (mNeedsToInitDimensions) {
|
| - mNeedsToInitDimensions = false;
|
| - initDimensions();
|
| - }
|
| -
|
| - canvas.save();
|
| - // Calculate the elapsed fraction of animation.
|
| - float time = (SystemClock.uptimeMillis() - mAnimationStartTime + mTimeLeft) /
|
| - ((float) ANIMATION_DURATION);
|
| - time = constrain(time, 0, 1);
|
| - if (time >= 1) {
|
| - mAnimating = false;
|
| - if (!isShowing()) {
|
| - hideImmediately();
|
| - return;
|
| - }
|
| - } else {
|
| - invalidate();
|
| - }
|
| -
|
| - // Fraction of the animation to actally show.
|
| - float fractionAnimation;
|
| - if (mShowing) {
|
| - fractionAnimation = mShowInterpolator.getInterpolation(time);
|
| - } else {
|
| - fractionAnimation = mHideInterpolator.getInterpolation(time);
|
| - }
|
| -
|
| - // Draw a faded color over the entire view to fade out the original content, increasing
|
| - // the alpha value as fractionAnimation increases.
|
| - // TODO(nileshagrawal): We should use time here instead of fractionAnimation
|
| - // as fractionAnimaton is interpolated and can go over 1.
|
| - canvas.drawARGB((int) (80 * fractionAnimation), 0, 0, 0);
|
| - canvas.save();
|
| -
|
| - // Since we want the content to appear directly above its counterpart we need to make
|
| - // sure that it starts out at exactly the same size as it appears in the page,
|
| - // i.e. scale grows from 1/mScale to 1. Note that extrusion values are already zoomed
|
| - // with mScale.
|
| - float scale = fractionAnimation * (mScale - 1.0f) / mScale + 1.0f / mScale;
|
| -
|
| - // Since we want the content to appear directly above its counterpart on the
|
| - // page, we need to remove the mShiftX/Y effect at the beginning of the animation.
|
| - // The unshifting decreases with the animation.
|
| - float unshiftX = -mShiftX * (1.0f - fractionAnimation) / mScale;
|
| - float unshiftY = -mShiftY * (1.0f - fractionAnimation) / mScale;
|
| -
|
| - // Compute the rect to show.
|
| - RectF rect = new RectF();
|
| - rect.left = mTouch.x - mLeftExtrusion * scale + unshiftX;
|
| - rect.top = mTouch.y - mTopExtrusion * scale + unshiftY;
|
| - rect.right = mTouch.x + mRightExtrusion * scale + unshiftX;
|
| - rect.bottom = mTouch.y + mBottomExtrusion * scale + unshiftY;
|
| - canvas.clipRect(rect);
|
| -
|
| - // Since the canvas transform APIs all pre-concat the transformations, this is done in
|
| - // reverse order. The canvas is first scaled up, then shifted the appropriate amount of
|
| - // pixels.
|
| - canvas.scale(scale, scale, rect.left, rect.top);
|
| - canvas.translate(mPopupScrollX, mPopupScrollY);
|
| - canvas.drawBitmap(mZoomedBitmap, rect.left, rect.top, null);
|
| - canvas.restore();
|
| - Drawable overlayNineTile = getOverlayDrawable(getContext());
|
| - overlayNineTile.setBounds((int) rect.left - sOverlayPadding.left,
|
| - (int) rect.top - sOverlayPadding.top,
|
| - (int) rect.right + sOverlayPadding.right,
|
| - (int) rect.bottom + sOverlayPadding.bottom);
|
| - // TODO(nileshagrawal): We should use time here instead of fractionAnimation
|
| - // as fractionAnimaton is interpolated and can go over 1.
|
| - int alpha = constrain((int) (fractionAnimation * 255), 0, 255);
|
| - overlayNineTile.setAlpha(alpha);
|
| - overlayNineTile.draw(canvas);
|
| - canvas.restore();
|
| - }
|
| -
|
| - /**
|
| - * Show the PopupZoomer view with given target bounds.
|
| - */
|
| - public void show(Rect rect) {
|
| - if (mShowing || mZoomedBitmap == null) return;
|
| -
|
| - setTargetBounds(rect);
|
| - startAnimation(true);
|
| - }
|
| -
|
| - /**
|
| - * Hide the PopupZoomer view.
|
| - * @param animation true if hide with animation.
|
| - */
|
| - public void hide(boolean animation) {
|
| - if (!mShowing) return;
|
| -
|
| - if (animation) {
|
| - startAnimation(false);
|
| - } else {
|
| - hideImmediately();
|
| - }
|
| - }
|
| -
|
| - /**
|
| - * Converts the coordinates to a point on the original un-zoomed view.
|
| - */
|
| - private PointF convertTouchPoint(float x, float y) {
|
| - x -= mShiftX;
|
| - y -= mShiftY;
|
| - x = mTouch.x + (x - mTouch.x - mPopupScrollX) / mScale;
|
| - y = mTouch.y + (y - mTouch.y - mPopupScrollY) / mScale;
|
| - return new PointF(x, y);
|
| - }
|
| -
|
| - /**
|
| - * Returns true if the point is inside the final drawable area for this popup zoomer.
|
| - */
|
| - private boolean isTouchOutsideArea(float x, float y) {
|
| - return !mClipRect.contains(x, y);
|
| - }
|
| -
|
| - @Override
|
| - public boolean onTouchEvent(MotionEvent event) {
|
| - mGestureDetector.onTouchEvent(event);
|
| - return true;
|
| - }
|
| -
|
| - private static class ReverseInterpolator implements Interpolator {
|
| - private final Interpolator mInterpolator;
|
| -
|
| - public ReverseInterpolator(Interpolator i) {
|
| - mInterpolator = i;
|
| - }
|
| -
|
| - @Override
|
| - public float getInterpolation(float input) {
|
| - input = 1.0f - input;
|
| - if (mInterpolator == null) return input;
|
| - return mInterpolator.getInterpolation(input);
|
| - }
|
| - }
|
| -}
|
|
|