summaryrefslogtreecommitdiffstats
path: root/src/com/android/camera/CropImage.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/camera/CropImage.java')
-rw-r--r--src/com/android/camera/CropImage.java780
1 files changed, 360 insertions, 420 deletions
diff --git a/src/com/android/camera/CropImage.java b/src/com/android/camera/CropImage.java
index 0932471..29d857c 100644
--- a/src/com/android/camera/CropImage.java
+++ b/src/com/android/camera/CropImage.java
@@ -43,7 +43,6 @@ import android.provider.MediaStore;
import android.util.AttributeSet;
import android.util.Config;
import android.util.Log;
-import android.view.Menu;
import android.view.MotionEvent;
import android.view.View;
import android.view.Window;
@@ -66,284 +65,21 @@ public class CropImage extends Activity {
private int mOutputX, mOutputY;
private boolean mDoFaceDetection = true;
private boolean mCircleCrop = false;
- private boolean mWaitingToPick;
+ boolean mWaitingToPick;
private boolean mScale;
- private boolean mSaving;
+ boolean mSaving;
private boolean mScaleUp = true;
- CropImageView mImageView;
- ContentResolver mContentResolver;
+ private CropImageView mImageView;
+ private ContentResolver mContentResolver;
- Bitmap mBitmap;
- Bitmap mCroppedImage;
+ private Bitmap mBitmap;
+ private Bitmap mCroppedImage;
HighlightView mCrop;
- IImage mImage;
+ private IImage mImage;
- public CropImage() {
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- return super.onCreateOptionsMenu(menu);
- }
-
- public static class CropImageView extends ImageViewTouchBase {
- ArrayList<HighlightView> mHighlightViews =
- new ArrayList<HighlightView>();
- HighlightView mMotionHighlightView = null;
- float mLastX, mLastY;
- int mMotionEdge;
-
- public CropImageView(Context context) {
- super(context);
- }
-
- @Override
- protected boolean doesScrolling() {
- return false;
- }
-
- @Override
- protected void onLayout(boolean changed, int left, int top,
- int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
- if (mBitmapDisplayed != null) {
- for (HighlightView hv : mHighlightViews) {
- hv.mMatrix.set(getImageMatrix());
- hv.invalidate();
- if (hv.mIsFocused) {
- centerBasedOnHighlightView(hv);
- }
- }
- }
- }
-
- public CropImageView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- protected void zoomTo(float scale, float centerX, float centerY) {
- super.zoomTo(scale, centerX, centerY);
- for (HighlightView hv : mHighlightViews) {
- hv.mMatrix.set(getImageMatrix());
- hv.invalidate();
- }
- }
-
- protected void zoomIn() {
- super.zoomIn();
- for (HighlightView hv : mHighlightViews) {
- hv.mMatrix.set(getImageMatrix());
- hv.invalidate();
- }
- }
-
- protected void zoomOut() {
- super.zoomOut();
- for (HighlightView hv : mHighlightViews) {
- hv.mMatrix.set(getImageMatrix());
- hv.invalidate();
- }
- }
-
-
- @Override
- protected boolean usePerfectFitBitmap() {
- return false;
- }
-
- @Override
- protected void postTranslate(float deltaX, float deltaY) {
- super.postTranslate(deltaX, deltaY);
- for (int i = 0; i < mHighlightViews.size(); i++) {
- HighlightView hv = mHighlightViews.get(i);
- hv.mMatrix.postTranslate(deltaX, deltaY);
- hv.invalidate();
- }
- }
-
- private void recomputeFocus(MotionEvent event) {
- for (int i = 0; i < mHighlightViews.size(); i++) {
- HighlightView hv = mHighlightViews.get(i);
- hv.setFocus(false);
- hv.invalidate();
- }
-
- for (int i = 0; i < mHighlightViews.size(); i++) {
- HighlightView hv = mHighlightViews.get(i);
- int edge = hv.getHit(event.getX(), event.getY());
- if (edge != HighlightView.GROW_NONE) {
- if (!hv.hasFocus()) {
- hv.setFocus(true);
- hv.invalidate();
- }
- break;
- }
- }
- invalidate();
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- CropImage cropImage = (CropImage) mContext;
- if (cropImage.mSaving) {
- return false;
- }
-
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- if (cropImage.mWaitingToPick) {
- recomputeFocus(event);
- } else {
- for (int i = 0; i < mHighlightViews.size(); i++) {
- HighlightView hv = mHighlightViews.get(i);
- int edge = hv.getHit(event.getX(), event.getY());
- if (edge != HighlightView.GROW_NONE) {
- mMotionEdge = edge;
- mMotionHighlightView = hv;
- mLastX = event.getX();
- mLastY = event.getY();
- mMotionHighlightView.setMode(
- edge == HighlightView.MOVE
- ? HighlightView.ModifyMode.Move
- : HighlightView.ModifyMode.Grow);
- break;
- }
- }
- }
- break;
- case MotionEvent.ACTION_UP:
- if (cropImage.mWaitingToPick) {
- for (int i = 0; i < mHighlightViews.size(); i++) {
- HighlightView hv = mHighlightViews.get(i);
- if (hv.hasFocus()) {
- cropImage.mCrop = hv;
- for (int j = 0; j < mHighlightViews.size();
- j++) {
- if (j == i) {
- continue;
- }
- mHighlightViews.get(j).setHidden(true);
- }
- centerBasedOnHighlightView(hv);
- ((CropImage) mContext).mWaitingToPick = false;
- return true;
- }
- }
- } else if (mMotionHighlightView != null) {
- centerBasedOnHighlightView(mMotionHighlightView);
- mMotionHighlightView.setMode(
- HighlightView.ModifyMode.None);
- }
- mMotionHighlightView = null;
- break;
- case MotionEvent.ACTION_MOVE:
- if (cropImage.mWaitingToPick) {
- recomputeFocus(event);
- } else if (mMotionHighlightView != null) {
- mMotionHighlightView.handleMotion(mMotionEdge,
- event.getX() - mLastX,
- event.getY() - mLastY);
- mLastX = event.getX();
- mLastY = event.getY();
-
- if (true) {
- // This section of code is optional. It has some
- // user benefit in that moving the crop rectangle
- // against the edge of the screen causes scrolling
- // but it means that the crop rectangle is no longer
- // fixed under the user's finger.
- ensureVisible(mMotionHighlightView);
- }
- }
- break;
- }
-
- switch (event.getAction()) {
- case MotionEvent.ACTION_UP:
- center(true, true, true);
- break;
- case MotionEvent.ACTION_MOVE:
- // if we're not zoomed then there's no point in even
- // allowing the user to move the image around. This call
- // to center puts it back to the normalized location (with
- // false meaning don't animate).
- if (getScale() == 1F) {
- center(true, true, false);
- }
- break;
- }
-
- return true;
- }
-
- private void ensureVisible(HighlightView hv) {
- Rect r = hv.mDrawRect;
-
- int panDeltaX1 = Math.max(0, mLeft - r.left);
- int panDeltaX2 = Math.min(0, mRight - r.right);
-
- int panDeltaY1 = Math.max(0, mTop - r.top);
- int panDeltaY2 = Math.min(0, mBottom - r.bottom);
-
- int panDeltaX = panDeltaX1 != 0 ? panDeltaX1 : panDeltaX2;
- int panDeltaY = panDeltaY1 != 0 ? panDeltaY1 : panDeltaY2;
-
- if (panDeltaX != 0 || panDeltaY != 0) {
- panBy(panDeltaX, panDeltaY);
- }
- }
-
- private void centerBasedOnHighlightView(HighlightView hv) {
- Rect drawRect = hv.mDrawRect;
-
- float width = drawRect.width();
- float height = drawRect.height();
-
- float thisWidth = getWidth();
- float thisHeight = getHeight();
-
- float z1 = thisWidth / width * .6F;
- float z2 = thisHeight / height * .6F;
-
- float zoom = Math.min(z1, z2);
- zoom = zoom * this.getScale();
- zoom = Math.max(1F, zoom);
-
- if ((Math.abs(zoom - getScale()) / zoom) > .1) {
- float [] coordinates = new float[] {hv.mCropRect.centerX(),
- hv.mCropRect.centerY()};
- getImageMatrix().mapPoints(coordinates);
- zoomTo(zoom, coordinates[0], coordinates[1], 300F);
- }
-
- ensureVisible(hv);
- }
-
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- for (int i = 0; i < mHighlightViews.size(); i++) {
- mHighlightViews.get(i).draw(canvas);
- }
- }
-
- public HighlightView get(int i) {
- return mHighlightViews.get(i);
- }
-
- public int size() {
- return mHighlightViews.size();
- }
-
- public void add(HighlightView hv) {
- mHighlightViews.add(hv);
- invalidate();
- }
- }
-
- private void fillCanvas(int width, int height, Canvas c) {
+ private static void fillCanvas(int width, int height, Canvas c) {
Paint paint = new Paint();
paint.setColor(0x00000000); // pure alpha
paint.setStyle(android.graphics.Paint.Style.FILL);
@@ -365,7 +101,7 @@ public class CropImage extends Activity {
MenuHelper.showStorageToast(this);
try {
- android.content.Intent intent = getIntent();
+ Intent intent = getIntent();
Bundle extras = intent.getExtras();
if (Config.LOGV) {
Log.v(TAG, "extras are " + extras);
@@ -425,46 +161,9 @@ public class CropImage extends Activity {
mHandler.postDelayed(new Runnable() {
public void run() {
- if (isFinishing()) {
- return;
- }
- mFaceDetectionDialog = ProgressDialog.show(CropImage.this,
- null,
- getResources().getString(
- R.string.runningFaceDetection),
- true, false);
- mImageView.setImageBitmapResetBase(mBitmap, true, true);
- if (mImageView.getScale() == 1F) {
- mImageView.center(true, true, false);
- }
-
- new Thread(new Runnable() {
- public void run() {
- final Bitmap b = mImage != null
- ? mImage.fullSizeBitmap(500)
- : mBitmap;
- if (Config.LOGV) {
- Log.v(TAG, "back from fullSizeBitmap(500) "
- + "with bitmap of size " + b.getWidth()
- + " / " + b.getHeight());
- }
- mHandler.post(new Runnable() {
- public void run() {
- if (b != mBitmap && b != null) {
- mBitmap = b;
- mImageView.setImageBitmapResetBase(b,
- true, false);
- }
- if (mImageView.getScale() == 1F) {
- mImageView.center(true, true, false);
- }
-
- new Thread(mRunFaceDetection).start();
- }
- });
- }
- }).start();
- }}, 100);
+ startFaceDetection();
+ }
+ }, 100);
} catch (Exception e) {
Log.e(TAG, "Failed to load bitmap", e);
finish();
@@ -486,6 +185,45 @@ public class CropImage extends Activity {
});
}
+ private void startFaceDetection() {
+ if (isFinishing()) {
+ return;
+ }
+ mFaceDetectionDialog = ProgressDialog.show(CropImage.this, null,
+ getResources().getString(R.string.runningFaceDetection),
+ true, false);
+ mImageView.setImageBitmapResetBase(mBitmap, true, true);
+ if (mImageView.getScale() == 1F) {
+ mImageView.center(true, true, false);
+ }
+
+ new Thread(new Runnable() {
+ public void run() {
+ final Bitmap b = (mImage != null)
+ ? mImage.fullSizeBitmap(500)
+ : mBitmap;
+ if (Config.LOGV) {
+ Log.v(TAG, "back from fullSizeBitmap(500) "
+ + "with bitmap of size " + b.getWidth()
+ + " / " + b.getHeight());
+ }
+ mHandler.post(new Runnable() {
+ public void run() {
+ if (b != mBitmap && b != null) {
+ mBitmap = b;
+ mImageView.setImageBitmapResetBase(b, true, false);
+ }
+ if (mImageView.getScale() == 1F) {
+ mImageView.center(true, true, false);
+ }
+
+ new Thread(mRunFaceDetection).start();
+ }
+ });
+ }
+ }).start();
+ }
+
private void onSaveClicked() {
// TODO this code needs to change to use the decode/crop/encode single
// step api so that we don't require that the whole (possibly large)
@@ -531,9 +269,7 @@ public class CropImage extends Activity {
/* If the output is required to a specific size then scale or fill */
if (mOutputX != 0 && mOutputY != 0) {
-
if (mScale) {
-
/* Scale the image to the required dimensions */
mCroppedImage = ImageLoader.transform(new Matrix(),
mCroppedImage, mOutputX, mOutputY, mScaleUp);
@@ -562,6 +298,7 @@ public class CropImage extends Activity {
}
}
+ // Return the cropped image directly or save it to the specified URI.
Bundle myExtras = getIntent().getExtras();
if (myExtras != null && (myExtras.getParcelable("data") != null
|| myExtras.getBoolean("return-data"))) {
@@ -595,7 +332,6 @@ public class CropImage extends Activity {
mCroppedImage.compress(mSaveFormat, 75,
outputStream);
}
-
} catch (IOException ex) {
if (Config.LOGV) {
Log.v(TAG, "got IOException " + ex);
@@ -618,87 +354,66 @@ public class CropImage extends Activity {
extras.putString("rect",
mCrop.getCropRect().toString());
- // here we decide whether to create a new image or
- // modify the existing image
- if (false) {
- /*
- // this is the "modify" case
- ImageManager.IGetBoolean_cancelable cancelable =
- mImage.saveImageContents(mCroppedImage, null,
- null, null, mImage.getDateTaken(), 0, false);
- boolean didSave = cancelable.get();
- extras.putString("thumb1uri",
- mImage.thumbUri().toString());
+ java.io.File oldPath
+ = new java.io.File(mImage.getDataPath());
+ java.io.File directory
+ = new java.io.File(oldPath.getParent());
+
+ int x = 0;
+ String fileName = oldPath.getName();
+ fileName = fileName.substring(0,
+ fileName.lastIndexOf("."));
+
+ while (true) {
+ x += 1;
+ String candidate = directory.toString()
+ + "/" + fileName + "-" + x + ".jpg";
+ if (Config.LOGV) {
+ Log.v(TAG, "candidate is " + candidate);
+ }
+ boolean exists =
+ (new java.io.File(candidate)).exists();
+ if (!exists) {
+ break;
+ }
+ }
+
+ try {
+ Uri newUri = ImageManager
+ .instance()
+ .addImage(
+ CropImage.this,
+ getContentResolver(),
+ mImage.getTitle(),
+ mImage.getDescription(),
+ mImage.getDateTaken(),
+ null, // TODO this null is
+ // going to cause us to
+ // lose the location (gps)
+ 0, // TODO this is going to
+ // cause the orientation
+ // to reset
+ directory.toString(),
+ fileName + "-" + x + ".jpg");
+
+ IAddImageCancelable cancelable =
+ ImageManager.instance()
+ .storeImage(
+ newUri,
+ CropImage.this,
+ getContentResolver(),
+ 0, // TODO fix this orientation
+ mCroppedImage,
+ null);
+
+ cancelable.get();
setResult(RESULT_OK,
(new Intent())
- .setAction(mImage.fullSizeImageUri()
- .toString())
+ .setAction(newUri.toString())
.putExtras(extras));
- */
- } else {
- // this is the "new image" case
- java.io.File oldPath
- = new java.io.File(mImage.getDataPath());
- java.io.File directory
- = new java.io.File(oldPath.getParent());
-
- int x = 0;
- String fileName = oldPath.getName();
- fileName = fileName.substring(0,
- fileName.lastIndexOf("."));
-
- while (true) {
- x += 1;
- String candidate = directory.toString()
- + "/" + fileName + "-" + x + ".jpg";
- if (Config.LOGV) {
- Log.v(TAG, "candidate is "
- + candidate);
- }
- boolean exists =
- (new java.io.File(candidate)).exists();
- if (!exists) {
- break;
- }
- }
-
- try {
- Uri newUri = ImageManager
- .instance()
- .addImage(
- CropImage.this,
- getContentResolver(),
- mImage.getTitle(),
- mImage.getDescription(),
- mImage.getDateTaken(),
- null, // TODO this null is
- // going to cause us to
- // lose the location (gps)
- 0, // TODO this is going to
- // cause the orientation
- // to reset
- directory.toString(),
- fileName + "-" + x + ".jpg");
-
- IAddImageCancelable cancelable =
- ImageManager.instance()
- .storeImage(
- newUri,
- CropImage.this,
- getContentResolver(),
- 0, // TODO fix this orientation
- mCroppedImage,
- null);
-
- cancelable.get();
- setResult(RESULT_OK,
- (new Intent())
- .setAction(newUri.toString())
- .putExtras(extras));
- } catch (Exception ex) {
- // basically ignore this or put up
- // some ui saying we failed
- }
+ } catch (Exception ex) {
+ // basically ignore this or put up
+ // some ui saying we failed
}
}
finish();
@@ -709,20 +424,15 @@ public class CropImage extends Activity {
}
}
- @Override
- public void onResume() {
- super.onResume();
- }
-
Handler mHandler = new Handler();
Runnable mRunFaceDetection = new Runnable() {
float mScale = 1F;
- RectF mUnion = null;
Matrix mImageMatrix;
FaceDetector.Face[] mFaces = new FaceDetector.Face[3];
int mNumFaces;
+ // For each face, we create a HightlightView for it.
private void handleFace(FaceDetector.Face f) {
PointF midPoint = new PointF();
@@ -734,7 +444,7 @@ public class CropImage extends Activity {
int midX = (int) midPoint.x;
int midY = (int) midPoint.y;
- HighlightView hv = makeHighlightView();
+ HighlightView hv = new HighlightView(mImageView);
int width = mBitmap.getWidth();
int height = mBitmap.getHeight();
@@ -764,21 +474,12 @@ public class CropImage extends Activity {
hv.setup(mImageMatrix, imageRect, faceRect, mCircleCrop,
mAspectX != 0 && mAspectY != 0);
- if (mUnion == null) {
- mUnion = new RectF(faceRect);
- } else {
- mUnion.union(faceRect);
- }
-
mImageView.add(hv);
}
- private HighlightView makeHighlightView() {
- return new HighlightView(mImageView);
- }
-
+ // Create a default HightlightView if we found no face in the picture.
private void makeDefault() {
- HighlightView hv = makeHighlightView();
+ HighlightView hv = new HighlightView(mImageView);
int width = mBitmap.getWidth();
int height = mBitmap.getHeight();
@@ -792,10 +493,8 @@ public class CropImage extends Activity {
if (mAspectX != 0 && mAspectY != 0) {
if (mAspectX > mAspectY) {
cropHeight = cropWidth * mAspectY / mAspectX;
-// Log.v(TAG, "adjusted cropHeight to " + cropHeight);
} else {
cropWidth = cropHeight * mAspectX / mAspectY;
-// Log.v(TAG, "adjusted cropWidth to " + cropWidth);
}
}
@@ -808,12 +507,12 @@ public class CropImage extends Activity {
mImageView.add(hv);
}
+ // Scale the image down for faster face detection.
private Bitmap prepareBitmap() {
if (mBitmap == null) {
return null;
}
- // scale the image down for faster face detection
// 256 pixels wide is enough.
if (mBitmap.getWidth() > 256) {
mScale = 256.0F / (float) mBitmap.getWidth();
@@ -832,11 +531,8 @@ public class CropImage extends Activity {
mScale = 1.0F / mScale;
if (faceBitmap != null && mDoFaceDetection) {
FaceDetector detector = new FaceDetector(faceBitmap.getWidth(),
- faceBitmap.getHeight(), mFaces.length);
+ faceBitmap.getHeight(), mFaces.length);
mNumFaces = detector.findFaces(faceBitmap, mFaces);
- if (Config.LOGV) {
- Log.v(TAG, "numFaces is " + mNumFaces);
- }
}
mHandler.post(new Runnable() {
public void run() {
@@ -864,7 +560,6 @@ public class CropImage extends Activity {
}
}
});
-
}
};
@@ -888,3 +583,248 @@ public class CropImage extends Activity {
}
}
}
+
+class CropImageView extends ImageViewTouchBase {
+ ArrayList<HighlightView> mHighlightViews = new ArrayList<HighlightView>();
+ HighlightView mMotionHighlightView = null;
+ float mLastX, mLastY;
+ int mMotionEdge;
+
+ @Override
+ protected boolean doesScrolling() {
+ return false;
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top,
+ int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ if (mBitmapDisplayed != null) {
+ for (HighlightView hv : mHighlightViews) {
+ hv.mMatrix.set(getImageMatrix());
+ hv.invalidate();
+ if (hv.mIsFocused) {
+ centerBasedOnHighlightView(hv);
+ }
+ }
+ }
+ }
+
+ public CropImageView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ protected void zoomTo(float scale, float centerX, float centerY) {
+ super.zoomTo(scale, centerX, centerY);
+ for (HighlightView hv : mHighlightViews) {
+ hv.mMatrix.set(getImageMatrix());
+ hv.invalidate();
+ }
+ }
+
+ protected void zoomIn() {
+ super.zoomIn();
+ for (HighlightView hv : mHighlightViews) {
+ hv.mMatrix.set(getImageMatrix());
+ hv.invalidate();
+ }
+ }
+
+ protected void zoomOut() {
+ super.zoomOut();
+ for (HighlightView hv : mHighlightViews) {
+ hv.mMatrix.set(getImageMatrix());
+ hv.invalidate();
+ }
+ }
+
+ @Override
+ protected boolean usePerfectFitBitmap() {
+ return false;
+ }
+
+ @Override
+ protected void postTranslate(float deltaX, float deltaY) {
+ super.postTranslate(deltaX, deltaY);
+ for (int i = 0; i < mHighlightViews.size(); i++) {
+ HighlightView hv = mHighlightViews.get(i);
+ hv.mMatrix.postTranslate(deltaX, deltaY);
+ hv.invalidate();
+ }
+ }
+
+ // According to the event's position, change the focus to the first
+ // hitting cropping rectangle.
+ private void recomputeFocus(MotionEvent event) {
+ for (int i = 0; i < mHighlightViews.size(); i++) {
+ HighlightView hv = mHighlightViews.get(i);
+ hv.setFocus(false);
+ hv.invalidate();
+ }
+
+ for (int i = 0; i < mHighlightViews.size(); i++) {
+ HighlightView hv = mHighlightViews.get(i);
+ int edge = hv.getHit(event.getX(), event.getY());
+ if (edge != HighlightView.GROW_NONE) {
+ if (!hv.hasFocus()) {
+ hv.setFocus(true);
+ hv.invalidate();
+ }
+ break;
+ }
+ }
+ invalidate();
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ CropImage cropImage = (CropImage) mContext;
+ if (cropImage.mSaving) {
+ return false;
+ }
+
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ if (cropImage.mWaitingToPick) {
+ recomputeFocus(event);
+ } else {
+ for (int i = 0; i < mHighlightViews.size(); i++) {
+ HighlightView hv = mHighlightViews.get(i);
+ int edge = hv.getHit(event.getX(), event.getY());
+ if (edge != HighlightView.GROW_NONE) {
+ mMotionEdge = edge;
+ mMotionHighlightView = hv;
+ mLastX = event.getX();
+ mLastY = event.getY();
+ mMotionHighlightView.setMode(
+ (edge == HighlightView.MOVE)
+ ? HighlightView.ModifyMode.Move
+ : HighlightView.ModifyMode.Grow);
+ break;
+ }
+ }
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ if (cropImage.mWaitingToPick) {
+ for (int i = 0; i < mHighlightViews.size(); i++) {
+ HighlightView hv = mHighlightViews.get(i);
+ if (hv.hasFocus()) {
+ cropImage.mCrop = hv;
+ for (int j = 0; j < mHighlightViews.size(); j++) {
+ if (j == i) {
+ continue;
+ }
+ mHighlightViews.get(j).setHidden(true);
+ }
+ centerBasedOnHighlightView(hv);
+ ((CropImage) mContext).mWaitingToPick = false;
+ return true;
+ }
+ }
+ } else if (mMotionHighlightView != null) {
+ centerBasedOnHighlightView(mMotionHighlightView);
+ mMotionHighlightView.setMode(
+ HighlightView.ModifyMode.None);
+ }
+ mMotionHighlightView = null;
+ break;
+ case MotionEvent.ACTION_MOVE:
+ if (cropImage.mWaitingToPick) {
+ recomputeFocus(event);
+ } else if (mMotionHighlightView != null) {
+ mMotionHighlightView.handleMotion(mMotionEdge,
+ event.getX() - mLastX,
+ event.getY() - mLastY);
+ mLastX = event.getX();
+ mLastY = event.getY();
+
+ if (true) {
+ // This section of code is optional. It has some user
+ // benefit in that moving the crop rectangle against
+ // the edge of the screen causes scrolling but it means
+ // that the crop rectangle is no longer fixed under
+ // the user's finger.
+ ensureVisible(mMotionHighlightView);
+ }
+ }
+ break;
+ }
+
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_UP:
+ center(true, true, true);
+ break;
+ case MotionEvent.ACTION_MOVE:
+ // if we're not zoomed then there's no point in even allowing
+ // the user to move the image around. This call to center puts
+ // it back to the normalized location (with false meaning don't
+ // animate).
+ if (getScale() == 1F) {
+ center(true, true, false);
+ }
+ break;
+ }
+
+ return true;
+ }
+
+ // Pan the displayed image to make sure the cropping rectangle is visible.
+ private void ensureVisible(HighlightView hv) {
+ Rect r = hv.mDrawRect;
+
+ int panDeltaX1 = Math.max(0, mLeft - r.left);
+ int panDeltaX2 = Math.min(0, mRight - r.right);
+
+ int panDeltaY1 = Math.max(0, mTop - r.top);
+ int panDeltaY2 = Math.min(0, mBottom - r.bottom);
+
+ int panDeltaX = panDeltaX1 != 0 ? panDeltaX1 : panDeltaX2;
+ int panDeltaY = panDeltaY1 != 0 ? panDeltaY1 : panDeltaY2;
+
+ if (panDeltaX != 0 || panDeltaY != 0) {
+ panBy(panDeltaX, panDeltaY);
+ }
+ }
+
+ // If the cropping rectangle's size changed significantly, change the
+ // view's center and scale according to the cropping rectangle.
+ private void centerBasedOnHighlightView(HighlightView hv) {
+ Rect drawRect = hv.mDrawRect;
+
+ float width = drawRect.width();
+ float height = drawRect.height();
+
+ float thisWidth = getWidth();
+ float thisHeight = getHeight();
+
+ float z1 = thisWidth / width * .6F;
+ float z2 = thisHeight / height * .6F;
+
+ float zoom = Math.min(z1, z2);
+ zoom = zoom * this.getScale();
+ zoom = Math.max(1F, zoom);
+
+ if ((Math.abs(zoom - getScale()) / zoom) > .1) {
+ float [] coordinates = new float[] {hv.mCropRect.centerX(),
+ hv.mCropRect.centerY()};
+ getImageMatrix().mapPoints(coordinates);
+ zoomTo(zoom, coordinates[0], coordinates[1], 300F);
+ }
+
+ ensureVisible(hv);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ for (int i = 0; i < mHighlightViews.size(); i++) {
+ mHighlightViews.get(i).draw(canvas);
+ }
+ }
+
+ public void add(HighlightView hv) {
+ mHighlightViews.add(hv);
+ invalidate();
+ }
+}