X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=src%2Fcom%2Fandroid%2Fgallery3d%2Ffiltershow%2Fimageshow%2FImageShow.java;h=2022ffd7e74febc7d7f8eab72c01415336a99f75;hb=fac21a096afbe8eb517726cf4f9f093eade87ddc;hp=77eaf4dc7b864c9f7ade100e5fb1754de838bf29;hpb=051d52911909ffa38cdaa213c8b391d3c63b693a;p=android-x86%2Fpackages-apps-Gallery2.git diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java index 77eaf4dc7..2022ffd7e 100644 --- a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java +++ b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java @@ -16,6 +16,8 @@ package com.android.gallery3d.filtershow.imageshow; +import android.animation.Animator; +import android.animation.ValueAnimator; import android.content.Context; import android.content.res.Resources; import android.graphics.Bitmap; @@ -27,9 +29,12 @@ import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Point; import android.graphics.Rect; +import android.graphics.RectF; import android.graphics.Shader; import android.graphics.drawable.NinePatchDrawable; +import android.support.v4.widget.EdgeEffectCompat; import android.util.AttributeSet; +import android.util.Log; import android.view.GestureDetector; import android.view.GestureDetector.OnDoubleTapListener; import android.view.GestureDetector.OnGestureListener; @@ -48,7 +53,6 @@ import com.android.gallery3d.filtershow.tools.SaveImage; import java.io.File; import java.util.ArrayList; -import java.util.Collection; public class ImageShow extends View implements OnGestureListener, ScaleGestureDetector.OnScaleGestureListener, @@ -91,6 +95,21 @@ public class ImageShow extends View implements OnGestureListener, Point mOriginalTranslation = new Point(); float mOriginalScale; float mStartFocusX, mStartFocusY; + + private EdgeEffectCompat mEdgeEffect = null; + private static final int EDGE_LEFT = 1; + private static final int EDGE_TOP = 2; + private static final int EDGE_RIGHT = 3; + private static final int EDGE_BOTTOM = 4; + private int mCurrentEdgeEffect = 0; + private int mEdgeSize = 100; + + private static final int mAnimationSnapDelay = 200; + private static final int mAnimationZoomDelay = 400; + private ValueAnimator mAnimatorScale = null; + private ValueAnimator mAnimatorTranslateX = null; + private ValueAnimator mAnimatorTranslateY = null; + private enum InteractionMode { NONE, SCALE, @@ -163,11 +182,14 @@ public class ImageShow extends View implements OnGestureListener, Bitmap mask = BitmapFactory.decodeResource(res, R.drawable.spot_mask); sMask = convertToAlphaMask(mask); } + mEdgeEffect = new EdgeEffectCompat(context); + mEdgeSize = res.getDimensionPixelSize(R.dimen.edge_glow_size); } public void attach() { MasterImage.getImage().addObserver(this); bindAsImageLoadListener(); + MasterImage.getImage().resetGeometryImages(false); } public void detach() { @@ -231,55 +253,84 @@ public class ImageShow extends View implements OnGestureListener, @Override public void onDraw(Canvas canvas) { + mPaint.reset(); + mPaint.setAntiAlias(true); + mPaint.setFilterBitmap(true); MasterImage.getImage().setImageShowSize( getWidth() - 2*mShadowMargin, getHeight() - 2*mShadowMargin); - float cx = canvas.getWidth()/2.0f; - float cy = canvas.getHeight()/2.0f; - float scaleFactor = MasterImage.getImage().getScaleFactor(); - Point translation = MasterImage.getImage().getTranslation(); + MasterImage img = MasterImage.getImage(); + // Hide the loading indicator as needed + if (mActivity.isLoadingVisible() && getFilteredImage() != null) { + if ((img.getLoadedPreset() == null) + || (img.getLoadedPreset() != null + && img.getLoadedPreset().equals(img.getCurrentPreset()))) { + mActivity.stopLoadingIndicator(); + } else if (img.getLoadedPreset() != null) { + return; + } + mActivity.stopLoadingIndicator(); + } canvas.save(); mShadowDrawn = false; - canvas.save(); - // TODO: center scale on gesture - canvas.scale(scaleFactor, scaleFactor, cx, cy); - canvas.translate(translation.x, translation.y); Bitmap highresPreview = MasterImage.getImage().getHighresImage(); + Bitmap fullHighres = MasterImage.getImage().getPartialImage(); boolean isDoingNewLookAnimation = MasterImage.getImage().onGoingNewLookAnimation(); - if (!isDoingNewLookAnimation && highresPreview != null) { - drawImage(canvas, highresPreview, true); + if (highresPreview == null || isDoingNewLookAnimation) { + drawImageAndAnimate(canvas, getFilteredImage()); } else { - drawImage(canvas, getFilteredImage(), true); + drawImageAndAnimate(canvas, highresPreview); } + + drawHighresImage(canvas, fullHighres); + drawCompareImage(canvas, getGeometryOnlyImage()); + canvas.restore(); - Bitmap partialPreview = MasterImage.getImage().getPartialImage(); - if (!isDoingNewLookAnimation && partialPreview != null) { + if (!mEdgeEffect.isFinished()) { canvas.save(); - Rect originalBounds = MasterImage.getImage().getOriginalBounds(); - Collection geo = MasterImage.getImage().getPreset() - .getGeometryFilters(); - - Matrix compensation = GeometryMathUtils.getPartialToScreenMatrix(geo, - originalBounds, getWidth(), getHeight(), - partialPreview.getWidth(), partialPreview.getHeight()); - canvas.drawBitmap(partialPreview, compensation, null); + float dx = (getHeight() - getWidth()) / 2f; + if (getWidth() > getHeight()) { + dx = - (getWidth() - getHeight()) / 2f; + } + if (mCurrentEdgeEffect == EDGE_BOTTOM) { + canvas.rotate(180, getWidth()/2, getHeight()/2); + } else if (mCurrentEdgeEffect == EDGE_RIGHT) { + canvas.rotate(90, getWidth()/2, getHeight()/2); + canvas.translate(0, dx); + } else if (mCurrentEdgeEffect == EDGE_LEFT) { + canvas.rotate(270, getWidth()/2, getHeight()/2); + canvas.translate(0, dx); + } + if (mCurrentEdgeEffect != 0) { + mEdgeEffect.draw(canvas); + } canvas.restore(); + invalidate(); + } else { + mCurrentEdgeEffect = 0; } + } - canvas.save(); - canvas.scale(scaleFactor, scaleFactor, cx, cy); - canvas.translate(translation.x, translation.y); - drawPartialImage(canvas, getGeometryOnlyImage()); - canvas.restore(); - - canvas.restore(); + private void drawHighresImage(Canvas canvas, Bitmap fullHighres) { + Matrix originalToScreen = MasterImage.getImage().originalImageToScreen(); + if (fullHighres != null && originalToScreen != null) { + Matrix screenToOriginal = new Matrix(); + originalToScreen.invert(screenToOriginal); + Rect rBounds = new Rect(); + rBounds.set(MasterImage.getImage().getPartialBounds()); + if (fullHighres != null) { + originalToScreen.preTranslate(rBounds.left, rBounds.top); + canvas.clipRect(mImageBounds); + canvas.drawBitmap(fullHighres, originalToScreen, mPaint); + } + } } public void resetImageCaches(ImageShow caller) { @@ -298,52 +349,83 @@ public class ImageShow extends View implements OnGestureListener, return MasterImage.getImage().getFilteredImage(); } - public void drawImage(Canvas canvas, Bitmap image, boolean updateBounds) { + public void drawImageAndAnimate(Canvas canvas, + Bitmap image) { if (image == null) { return; } + MasterImage master = MasterImage.getImage(); + Matrix m = master.computeImageToScreen(image, 0, false); + if (m == null) { + return; + } - Rect d = computeImageBounds(image.getWidth(), image.getHeight()); + canvas.save(); - if (updateBounds) { - mImageBounds = d; + RectF d = new RectF(0, 0, image.getWidth(), image.getHeight()); + m.mapRect(d); + d.roundOut(mImageBounds); + + boolean showAnimatedImage = master.onGoingNewLookAnimation(); + if (!showAnimatedImage && mDidStartAnimation) { + // animation ended, but do we have the correct image to show? + if (master.getPreset().equals(master.getCurrentPreset())) { + // we do, let's stop showing the animated image + mDidStartAnimation = false; + MasterImage.getImage().resetAnimBitmap(); + } else { + showAnimatedImage = true; + } + } else if (showAnimatedImage) { + mDidStartAnimation = true; } - float centerX = mShadowMargin + (getWidth() - 2 * mShadowMargin) / 2; - float centerY = mShadowMargin + (getHeight() - 2 * mShadowMargin) / 2; + if (showAnimatedImage) { + canvas.save(); + + // Animation uses the image before the change + Bitmap previousImage = master.getPreviousImage(); + Matrix mp = master.computeImageToScreen(previousImage, 0, false); + RectF dp = new RectF(0, 0, previousImage.getWidth(), previousImage.getHeight()); + mp.mapRect(dp); + Rect previousBounds = new Rect(); + dp.roundOut(previousBounds); + float centerX = dp.centerX(); + float centerY = dp.centerY(); + boolean needsToDrawImage = true; - MasterImage master = MasterImage.getImage(); - canvas.save(); - if (master.onGoingNewLookAnimation() - || mDidStartAnimation) { - mDidStartAnimation = true; if (master.getCurrentLookAnimation() - == MasterImage.CIRCLE_ANIMATION - && MasterImage.getImage().getPreviousImage() != null) { + == MasterImage.CIRCLE_ANIMATION) { float maskScale = MasterImage.getImage().getMaskScale(); - if (maskScale > 0.0f) { + if (maskScale >= 0.0f) { float maskW = sMask.getWidth() / 2.0f; float maskH = sMask.getHeight() / 2.0f; - float x = centerX - maskW * maskScale; - float y = centerY - maskH * maskScale; + Point point = mActivity.hintTouchPoint(this); + float maxMaskScale = 2 * Math.max(getWidth(), getHeight()) + / Math.min(maskW, maskH); + maskScale = maskScale * maxMaskScale; + float x = point.x - maskW * maskScale; + float y = point.y - maskH * maskScale; // Prepare the shader mShaderMatrix.reset(); mShaderMatrix.setScale(1.0f / maskScale, 1.0f / maskScale); - mShaderMatrix.preTranslate(-x + d.left, -y + d.top); - float scaleImageX = d.width() / (float) image.getWidth(); - float scaleImageY = d.height() / (float) image.getHeight(); + mShaderMatrix.preTranslate(-x + mImageBounds.left, -y + mImageBounds.top); + float scaleImageX = mImageBounds.width() / (float) image.getWidth(); + float scaleImageY = mImageBounds.height() / (float) image.getHeight(); mShaderMatrix.preScale(scaleImageX, scaleImageY); mMaskPaint.reset(); - mMaskPaint.setShader(createShader(image)); - mMaskPaint.getShader().setLocalMatrix(mShaderMatrix); + Shader maskShader = createShader(image); + maskShader.setLocalMatrix(mShaderMatrix); + mMaskPaint.setShader(maskShader); - drawImage(canvas, MasterImage.getImage().getPreviousImage()); + drawShadow(canvas, mImageBounds); // as needed + canvas.drawBitmap(previousImage, m, mPaint); + canvas.clipRect(mImageBounds); canvas.translate(x, y); canvas.scale(maskScale, maskScale); canvas.drawBitmap(sMask, 0, 0, mMaskPaint); - } else { - drawImage(canvas, image); + needsToDrawImage = false; } } else if (master.getCurrentLookAnimation() == MasterImage.ROTATE_ANIMATION) { @@ -356,7 +438,6 @@ public class ImageShow extends View implements OnGestureListener, + (finalScale * master.getAnimFraction()); canvas.rotate(master.getAnimRotationValue(), centerX, centerY); canvas.scale(finalScale, finalScale, centerX, centerY); - drawImage(canvas, master.getPreviousImage()); } else if (master.getCurrentLookAnimation() == MasterImage.MIRROR_ANIMATION) { if (master.getCurrentFilterRepresentation() @@ -392,33 +473,22 @@ public class ImageShow extends View implements OnGestureListener, } } } - drawImage(canvas, master.getPreviousImage()); } + + if (needsToDrawImage) { + drawShadow(canvas, previousBounds); // as needed + canvas.drawBitmap(previousImage, mp, mPaint); + } + + canvas.restore(); } else { - drawImage(canvas, image); + drawShadow(canvas, mImageBounds); // as needed + canvas.drawBitmap(image, m, mPaint); } - if (!master.onGoingNewLookAnimation() - && mDidStartAnimation - && !master.getPreviousPreset().equals(master.getCurrentPreset())) { - mDidStartAnimation = false; - MasterImage.getImage().resetAnimBitmap(); - } canvas.restore(); } - private void drawImage(Canvas canvas, Bitmap image) { - Rect d = computeImageBounds(image.getWidth(), image.getHeight()); - float scaleImageX = d.width() / (float) image.getWidth(); - float scaleImageY = d.height() / (float) image.getHeight(); - Matrix imageMatrix = new Matrix(); - imageMatrix.postScale(scaleImageX, scaleImageY); - imageMatrix.postTranslate(d.left, d.top); - drawShadow(canvas, d); - canvas.clipRect(d); - canvas.drawBitmap(image, imageMatrix, mPaint); - } - private Rect computeImageBounds(int imageWidth, int imageHeight) { float scale = GeometryMathUtils.scale(imageWidth, imageHeight, getWidth(), getHeight()); @@ -443,8 +513,9 @@ public class ImageShow extends View implements OnGestureListener, } } - public void drawPartialImage(Canvas canvas, Bitmap image) { - boolean showsOriginal = MasterImage.getImage().showsOriginal(); + public void drawCompareImage(Canvas canvas, Bitmap image) { + MasterImage master = MasterImage.getImage(); + boolean showsOriginal = master.showsOriginal(); if (!showsOriginal && !mTouchShowOriginal) return; canvas.save(); @@ -472,8 +543,20 @@ public class ImageShow extends View implements OnGestureListener, Rect d = new Rect(mImageBounds.left, mImageBounds.top, mImageBounds.left + px, mImageBounds.top + py); + if (mShowOriginalDirection == UNVEIL_HORIZONTAL) { + if (mTouchDown.x - mTouch.x > 0) { + d.set(mImageBounds.left + px, mImageBounds.top, + mImageBounds.right, mImageBounds.top + py); + } + } else { + if (mTouchDown.y - mTouch.y > 0) { + d.set(mImageBounds.left, mImageBounds.top + py, + mImageBounds.left + px, mImageBounds.bottom); + } + } canvas.clipRect(d); - drawImage(canvas, image, false); + Matrix m = master.computeImageToScreen(image, 0, false); + canvas.drawBitmap(image, m, mPaint); Paint paint = new Paint(); paint.setColor(Color.BLACK); paint.setStrokeWidth(3); @@ -566,7 +649,6 @@ public class ImageShow extends View implements OnGestureListener, Point translation = MasterImage.getImage().getTranslation(); translation.x = (int) (originalTranslation.x + translateX); translation.y = (int) (originalTranslation.y + translateY); - constrainTranslation(translation, scaleFactor); MasterImage.getImage().setTranslation(translation); mTouchShowOriginal = false; } else if (enableComparison() && !mOriginalDisabled @@ -577,7 +659,9 @@ public class ImageShow extends View implements OnGestureListener, } } - if (action == MotionEvent.ACTION_UP) { + if (action == MotionEvent.ACTION_UP + || action == MotionEvent.ACTION_CANCEL + || action == MotionEvent.ACTION_OUTSIDE) { mInteractionMode = InteractionMode.NONE; mTouchShowOriginal = false; mTouchDown.x = 0; @@ -589,10 +673,67 @@ public class ImageShow extends View implements OnGestureListener, MasterImage.getImage().resetTranslation(); } } + + float scaleFactor = MasterImage.getImage().getScaleFactor(); + Point translation = MasterImage.getImage().getTranslation(); + constrainTranslation(translation, scaleFactor); + MasterImage.getImage().setTranslation(translation); + invalidate(); return true; } + private void startAnimTranslation(int fromX, int toX, + int fromY, int toY, int delay) { + if (fromX == toX && fromY == toY) { + return; + } + if (mAnimatorTranslateX != null) { + mAnimatorTranslateX.cancel(); + } + if (mAnimatorTranslateY != null) { + mAnimatorTranslateY.cancel(); + } + mAnimatorTranslateX = ValueAnimator.ofInt(fromX, toX); + mAnimatorTranslateY = ValueAnimator.ofInt(fromY, toY); + mAnimatorTranslateX.setDuration(delay); + mAnimatorTranslateY.setDuration(delay); + mAnimatorTranslateX.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + Point translation = MasterImage.getImage().getTranslation(); + translation.x = (Integer) animation.getAnimatedValue(); + MasterImage.getImage().setTranslation(translation); + invalidate(); + } + }); + mAnimatorTranslateY.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + Point translation = MasterImage.getImage().getTranslation(); + translation.y = (Integer) animation.getAnimatedValue(); + MasterImage.getImage().setTranslation(translation); + invalidate(); + } + }); + mAnimatorTranslateX.start(); + mAnimatorTranslateY.start(); + } + + private void applyTranslationConstraints() { + float scaleFactor = MasterImage.getImage().getScaleFactor(); + Point translation = MasterImage.getImage().getTranslation(); + int x = translation.x; + int y = translation.y; + constrainTranslation(translation, scaleFactor); + + if (x != translation.x || y != translation.y) { + startAnimTranslation(x, translation.x, + y, translation.y, + mAnimationSnapDelay); + } + } + protected boolean enableComparison() { return true; } @@ -601,34 +742,130 @@ public class ImageShow extends View implements OnGestureListener, public boolean onDoubleTap(MotionEvent arg0) { mZoomIn = !mZoomIn; float scale = 1.0f; + final float x = arg0.getX(); + final float y = arg0.getY(); if (mZoomIn) { scale = MasterImage.getImage().getMaxScaleFactor(); } if (scale != MasterImage.getImage().getScaleFactor()) { - MasterImage.getImage().setScaleFactor(scale); - float translateX = (getWidth() / 2 - arg0.getX()); - float translateY = (getHeight() / 2 - arg0.getY()); + if (mAnimatorScale != null) { + mAnimatorScale.cancel(); + } + mAnimatorScale = ValueAnimator.ofFloat( + MasterImage.getImage().getScaleFactor(), + scale + ); + float translateX = (getWidth() / 2 - x); + float translateY = (getHeight() / 2 - y); Point translation = MasterImage.getImage().getTranslation(); - translation.x = (int) (mOriginalTranslation.x + translateX); - translation.y = (int) (mOriginalTranslation.y + translateY); + int startTranslateX = translation.x; + int startTranslateY = translation.y; + if (scale != 1.0f) { + translation.x = (int) (mOriginalTranslation.x + translateX); + translation.y = (int) (mOriginalTranslation.y + translateY); + } else { + translation.x = 0; + translation.y = 0; + } constrainTranslation(translation, scale); - MasterImage.getImage().setTranslation(translation); - invalidate(); + + startAnimTranslation(startTranslateX, translation.x, + startTranslateY, translation.y, + mAnimationZoomDelay); + mAnimatorScale.setDuration(mAnimationZoomDelay); + mAnimatorScale.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator animation) { + MasterImage.getImage().setScaleFactor((Float) animation.getAnimatedValue()); + invalidate(); + } + }); + mAnimatorScale.addListener(new Animator.AnimatorListener() { + @Override + public void onAnimationStart(Animator animation) { + } + + @Override + public void onAnimationEnd(Animator animation) { + applyTranslationConstraints(); + MasterImage.getImage().needsUpdatePartialPreview(); + invalidate(); + } + + @Override + public void onAnimationCancel(Animator animation) { + + } + + @Override + public void onAnimationRepeat(Animator animation) { + + } + }); + mAnimatorScale.start(); } return true; } private void constrainTranslation(Point translation, float scale) { - float maxTranslationX = getWidth() / scale; - float maxTranslationY = getHeight() / scale; - if (Math.abs(translation.x) > maxTranslationX) { - translation.x = (int) (Math.signum(translation.x) * - maxTranslationX); - if (Math.abs(translation.y) > maxTranslationY) { - translation.y = (int) (Math.signum(translation.y) * - maxTranslationY); + int currentEdgeEffect = 0; + if (scale <= 1) { + mCurrentEdgeEffect = 0; + mEdgeEffect.finish(); + return; + } + + Matrix originalToScreen = MasterImage.getImage().originalImageToScreen(); + Rect originalBounds = MasterImage.getImage().getOriginalBounds(); + RectF screenPos = new RectF(originalBounds); + originalToScreen.mapRect(screenPos); + + boolean rightConstraint = screenPos.right < getWidth() - mShadowMargin; + boolean leftConstraint = screenPos.left > mShadowMargin; + boolean topConstraint = screenPos.top > mShadowMargin; + boolean bottomConstraint = screenPos.bottom < getHeight() - mShadowMargin; + + if (screenPos.width() > getWidth()) { + if (rightConstraint && !leftConstraint) { + float tx = screenPos.right - translation.x * scale; + translation.x = (int) ((getWidth() - mShadowMargin - tx) / scale); + currentEdgeEffect = EDGE_RIGHT; + } else if (leftConstraint && !rightConstraint) { + float tx = screenPos.left - translation.x * scale; + translation.x = (int) ((mShadowMargin - tx) / scale); + currentEdgeEffect = EDGE_LEFT; + } + } else { + float tx = screenPos.right - translation.x * scale; + float dx = (getWidth() - 2 * mShadowMargin - screenPos.width()) / 2f; + translation.x = (int) ((getWidth() - mShadowMargin - tx - dx) / scale); + } + + if (screenPos.height() > getHeight()) { + if (bottomConstraint && !topConstraint) { + float ty = screenPos.bottom - translation.y * scale; + translation.y = (int) ((getHeight() - mShadowMargin - ty) / scale); + currentEdgeEffect = EDGE_BOTTOM; + } else if (topConstraint && !bottomConstraint) { + float ty = screenPos.top - translation.y * scale; + translation.y = (int) ((mShadowMargin - ty) / scale); + currentEdgeEffect = EDGE_TOP; } + } else { + float ty = screenPos.bottom - translation.y * scale; + float dy = (getHeight()- 2 * mShadowMargin - screenPos.height()) / 2f; + translation.y = (int) ((getHeight() - mShadowMargin - ty - dy) / scale); + } + if (mCurrentEdgeEffect != currentEdgeEffect) { + if (mCurrentEdgeEffect == 0 || currentEdgeEffect != 0) { + mCurrentEdgeEffect = currentEdgeEffect; + mEdgeEffect.finish(); + } + mEdgeEffect.setSize(getWidth(), mEdgeSize); + } + if (currentEdgeEffect != 0) { + mEdgeEffect.onPull(mEdgeSize); } } @@ -692,8 +929,8 @@ public class ImageShow extends View implements OnGestureListener, if (scaleFactor > MasterImage.getImage().getMaxScaleFactor()) { scaleFactor = MasterImage.getImage().getMaxScaleFactor(); } - if (scaleFactor < 0.5) { - scaleFactor = 0.5f; + if (scaleFactor < 1.0f) { + scaleFactor = 1.0f; } MasterImage.getImage().setScaleFactor(scaleFactor); scaleFactor = img.getScaleFactor(); @@ -704,9 +941,7 @@ public class ImageShow extends View implements OnGestureListener, Point translation = MasterImage.getImage().getTranslation(); translation.x = (int) (mOriginalTranslation.x + translateX); translation.y = (int) (mOriginalTranslation.y + translateY); - constrainTranslation(translation, scaleFactor); MasterImage.getImage().setTranslation(translation); - invalidate(); return true; }