diff options
author | Michael Jurka <mikejurka@google.com> | 2013-12-10 23:47:28 +0100 |
---|---|---|
committer | Michael Jurka <mikejurka@google.com> | 2013-12-10 23:47:28 +0100 |
commit | 39de459a8621abfc91382ce7b4cdd37d09aaac12 (patch) | |
tree | 21357b3a777ad0ab5eb9f2c9628157897b44602b /src/com/android/launcher3/CropView.java | |
parent | 8e88cb84781907afb7cca80581fea2277264fd2c (diff) | |
download | android_packages_apps_Trebuchet-39de459a8621abfc91382ce7b4cdd37d09aaac12.tar.gz android_packages_apps_Trebuchet-39de459a8621abfc91382ce7b4cdd37d09aaac12.tar.bz2 android_packages_apps_Trebuchet-39de459a8621abfc91382ce7b4cdd37d09aaac12.zip |
Revert "Move wallpaper picker code to a separate directory"
This reverts commit 8e88cb84781907afb7cca80581fea2277264fd2c.
Diffstat (limited to 'src/com/android/launcher3/CropView.java')
-rw-r--r-- | src/com/android/launcher3/CropView.java | 322 |
1 files changed, 322 insertions, 0 deletions
diff --git a/src/com/android/launcher3/CropView.java b/src/com/android/launcher3/CropView.java new file mode 100644 index 000000000..578b8eafd --- /dev/null +++ b/src/com/android/launcher3/CropView.java @@ -0,0 +1,322 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.launcher3; + +import android.content.Context; +import android.graphics.Matrix; +import android.graphics.Point; +import android.graphics.RectF; +import android.util.AttributeSet; +import android.util.FloatMath; +import android.view.MotionEvent; +import android.view.ScaleGestureDetector; +import android.view.ScaleGestureDetector.OnScaleGestureListener; +import android.view.ViewConfiguration; +import android.view.ViewTreeObserver; +import android.view.ViewTreeObserver.OnGlobalLayoutListener; + +import com.android.photos.views.TiledImageRenderer.TileSource; +import com.android.photos.views.TiledImageView; + +public class CropView extends TiledImageView implements OnScaleGestureListener { + + private ScaleGestureDetector mScaleGestureDetector; + private long mTouchDownTime; + private float mFirstX, mFirstY; + private float mLastX, mLastY; + private float mCenterX, mCenterY; + private float mMinScale; + private boolean mTouchEnabled = true; + private RectF mTempEdges = new RectF(); + private float[] mTempPoint = new float[] { 0, 0 }; + private float[] mTempCoef = new float[] { 0, 0 }; + private float[] mTempAdjustment = new float[] { 0, 0 }; + private float[] mTempImageDims = new float[] { 0, 0 }; + private float[] mTempRendererCenter = new float[] { 0, 0 }; + TouchCallback mTouchCallback; + Matrix mRotateMatrix; + Matrix mInverseRotateMatrix; + + public interface TouchCallback { + void onTouchDown(); + void onTap(); + void onTouchUp(); + } + + public CropView(Context context) { + this(context, null); + } + + public CropView(Context context, AttributeSet attrs) { + super(context, attrs); + mScaleGestureDetector = new ScaleGestureDetector(context, this); + mRotateMatrix = new Matrix(); + mInverseRotateMatrix = new Matrix(); + } + + private float[] getImageDims() { + final float imageWidth = mRenderer.source.getImageWidth(); + final float imageHeight = mRenderer.source.getImageHeight(); + float[] imageDims = mTempImageDims; + imageDims[0] = imageWidth; + imageDims[1] = imageHeight; + mRotateMatrix.mapPoints(imageDims); + imageDims[0] = Math.abs(imageDims[0]); + imageDims[1] = Math.abs(imageDims[1]); + return imageDims; + } + + private void getEdgesHelper(RectF edgesOut) { + final float width = getWidth(); + final float height = getHeight(); + final float[] imageDims = getImageDims(); + final float imageWidth = imageDims[0]; + final float imageHeight = imageDims[1]; + + float initialCenterX = mRenderer.source.getImageWidth() / 2f; + float initialCenterY = mRenderer.source.getImageHeight() / 2f; + + float[] rendererCenter = mTempRendererCenter; + rendererCenter[0] = mCenterX - initialCenterX; + rendererCenter[1] = mCenterY - initialCenterY; + mRotateMatrix.mapPoints(rendererCenter); + rendererCenter[0] += imageWidth / 2; + rendererCenter[1] += imageHeight / 2; + + final float scale = mRenderer.scale; + float centerX = (width / 2f - rendererCenter[0] + (imageWidth - width) / 2f) + * scale + width / 2f; + float centerY = (height / 2f - rendererCenter[1] + (imageHeight - height) / 2f) + * scale + height / 2f; + float leftEdge = centerX - imageWidth / 2f * scale; + float rightEdge = centerX + imageWidth / 2f * scale; + float topEdge = centerY - imageHeight / 2f * scale; + float bottomEdge = centerY + imageHeight / 2f * scale; + + edgesOut.left = leftEdge; + edgesOut.right = rightEdge; + edgesOut.top = topEdge; + edgesOut.bottom = bottomEdge; + } + + public int getImageRotation() { + return mRenderer.rotation; + } + + public RectF getCrop() { + final RectF edges = mTempEdges; + getEdgesHelper(edges); + final float scale = mRenderer.scale; + + float cropLeft = -edges.left / scale; + float cropTop = -edges.top / scale; + float cropRight = cropLeft + getWidth() / scale; + float cropBottom = cropTop + getHeight() / scale; + + return new RectF(cropLeft, cropTop, cropRight, cropBottom); + } + + public Point getSourceDimensions() { + return new Point(mRenderer.source.getImageWidth(), mRenderer.source.getImageHeight()); + } + + public void setTileSource(TileSource source, Runnable isReadyCallback) { + super.setTileSource(source, isReadyCallback); + mCenterX = mRenderer.centerX; + mCenterY = mRenderer.centerY; + mRotateMatrix.reset(); + mRotateMatrix.setRotate(mRenderer.rotation); + mInverseRotateMatrix.reset(); + mInverseRotateMatrix.setRotate(-mRenderer.rotation); + updateMinScale(getWidth(), getHeight(), source, true); + } + + protected void onSizeChanged(int w, int h, int oldw, int oldh) { + updateMinScale(w, h, mRenderer.source, false); + } + + public void setScale(float scale) { + synchronized (mLock) { + mRenderer.scale = scale; + } + } + + private void updateMinScale(int w, int h, TileSource source, boolean resetScale) { + synchronized (mLock) { + if (resetScale) { + mRenderer.scale = 1; + } + if (source != null) { + final float[] imageDims = getImageDims(); + final float imageWidth = imageDims[0]; + final float imageHeight = imageDims[1]; + mMinScale = Math.max(w / imageWidth, h / imageHeight); + mRenderer.scale = + Math.max(mMinScale, resetScale ? Float.MIN_VALUE : mRenderer.scale); + } + } + } + + @Override + public boolean onScaleBegin(ScaleGestureDetector detector) { + return true; + } + + @Override + public boolean onScale(ScaleGestureDetector detector) { + // Don't need the lock because this will only fire inside of + // onTouchEvent + mRenderer.scale *= detector.getScaleFactor(); + mRenderer.scale = Math.max(mMinScale, mRenderer.scale); + invalidate(); + return true; + } + + @Override + public void onScaleEnd(ScaleGestureDetector detector) { + } + + public void moveToLeft() { + if (getWidth() == 0 || getHeight() == 0) { + final ViewTreeObserver observer = getViewTreeObserver(); + observer.addOnGlobalLayoutListener(new OnGlobalLayoutListener() { + public void onGlobalLayout() { + moveToLeft(); + getViewTreeObserver().removeOnGlobalLayoutListener(this); + } + }); + } + final RectF edges = mTempEdges; + getEdgesHelper(edges); + final float scale = mRenderer.scale; + mCenterX += Math.ceil(edges.left / scale); + updateCenter(); + } + + private void updateCenter() { + mRenderer.centerX = Math.round(mCenterX); + mRenderer.centerY = Math.round(mCenterY); + } + + public void setTouchEnabled(boolean enabled) { + mTouchEnabled = enabled; + } + + public void setTouchCallback(TouchCallback cb) { + mTouchCallback = cb; + } + + @Override + public boolean onTouchEvent(MotionEvent event) { + int action = event.getActionMasked(); + final boolean pointerUp = action == MotionEvent.ACTION_POINTER_UP; + final int skipIndex = pointerUp ? event.getActionIndex() : -1; + + // Determine focal point + float sumX = 0, sumY = 0; + final int count = event.getPointerCount(); + for (int i = 0; i < count; i++) { + if (skipIndex == i) + continue; + sumX += event.getX(i); + sumY += event.getY(i); + } + final int div = pointerUp ? count - 1 : count; + float x = sumX / div; + float y = sumY / div; + + if (action == MotionEvent.ACTION_DOWN) { + mFirstX = x; + mFirstY = y; + mTouchDownTime = System.currentTimeMillis(); + if (mTouchCallback != null) { + mTouchCallback.onTouchDown(); + } + } else if (action == MotionEvent.ACTION_UP) { + ViewConfiguration config = ViewConfiguration.get(getContext()); + + float squaredDist = (mFirstX - x) * (mFirstX - x) + (mFirstY - y) * (mFirstY - y); + float slop = config.getScaledTouchSlop() * config.getScaledTouchSlop(); + long now = System.currentTimeMillis(); + if (mTouchCallback != null) { + // only do this if it's a small movement + if (squaredDist < slop && + now < mTouchDownTime + ViewConfiguration.getTapTimeout()) { + mTouchCallback.onTap(); + } + mTouchCallback.onTouchUp(); + } + } + + if (!mTouchEnabled) { + return true; + } + + synchronized (mLock) { + mScaleGestureDetector.onTouchEvent(event); + switch (action) { + case MotionEvent.ACTION_MOVE: + float[] point = mTempPoint; + point[0] = (mLastX - x) / mRenderer.scale; + point[1] = (mLastY - y) / mRenderer.scale; + mInverseRotateMatrix.mapPoints(point); + mCenterX += point[0]; + mCenterY += point[1]; + updateCenter(); + invalidate(); + break; + } + if (mRenderer.source != null) { + // Adjust position so that the wallpaper covers the entire area + // of the screen + final RectF edges = mTempEdges; + getEdgesHelper(edges); + final float scale = mRenderer.scale; + + float[] coef = mTempCoef; + coef[0] = 1; + coef[1] = 1; + mRotateMatrix.mapPoints(coef); + float[] adjustment = mTempAdjustment; + mTempAdjustment[0] = 0; + mTempAdjustment[1] = 0; + if (edges.left > 0) { + adjustment[0] = edges.left / scale; + } else if (edges.right < getWidth()) { + adjustment[0] = (edges.right - getWidth()) / scale; + } + if (edges.top > 0) { + adjustment[1] = FloatMath.ceil(edges.top / scale); + } else if (edges.bottom < getHeight()) { + adjustment[1] = (edges.bottom - getHeight()) / scale; + } + for (int dim = 0; dim <= 1; dim++) { + if (coef[dim] > 0) adjustment[dim] = FloatMath.ceil(adjustment[dim]); + } + + mInverseRotateMatrix.mapPoints(adjustment); + mCenterX += adjustment[0]; + mCenterY += adjustment[1]; + updateCenter(); + } + } + + mLastX = x; + mLastY = y; + return true; + } +} |