CropImage.java revision 666ea1b28a76aeba74744148b15099254d918671
1666ea1b28a76aeba74744148b15099254d918671Owen Lin/*
2666ea1b28a76aeba74744148b15099254d918671Owen Lin * Copyright (C) 2007 The Android Open Source Project
3666ea1b28a76aeba74744148b15099254d918671Owen Lin *
4666ea1b28a76aeba74744148b15099254d918671Owen Lin * Licensed under the Apache License, Version 2.0 (the "License");
5666ea1b28a76aeba74744148b15099254d918671Owen Lin * you may not use this file except in compliance with the License.
6666ea1b28a76aeba74744148b15099254d918671Owen Lin * You may obtain a copy of the License at
7666ea1b28a76aeba74744148b15099254d918671Owen Lin *
8666ea1b28a76aeba74744148b15099254d918671Owen Lin *      http://www.apache.org/licenses/LICENSE-2.0
9666ea1b28a76aeba74744148b15099254d918671Owen Lin *
10666ea1b28a76aeba74744148b15099254d918671Owen Lin * Unless required by applicable law or agreed to in writing, software
11666ea1b28a76aeba74744148b15099254d918671Owen Lin * distributed under the License is distributed on an "AS IS" BASIS,
12666ea1b28a76aeba74744148b15099254d918671Owen Lin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13666ea1b28a76aeba74744148b15099254d918671Owen Lin * See the License for the specific language governing permissions and
14666ea1b28a76aeba74744148b15099254d918671Owen Lin * limitations under the License.
15666ea1b28a76aeba74744148b15099254d918671Owen Lin */
16666ea1b28a76aeba74744148b15099254d918671Owen Lin
17666ea1b28a76aeba74744148b15099254d918671Owen Linpackage com.android.camera;
18666ea1b28a76aeba74744148b15099254d918671Owen Lin
19666ea1b28a76aeba74744148b15099254d918671Owen Linimport com.android.camera.gallery.IImage;
20666ea1b28a76aeba74744148b15099254d918671Owen Linimport com.android.camera.gallery.IImageList;
21666ea1b28a76aeba74744148b15099254d918671Owen Lin
22666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.app.WallpaperManager;
23666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.content.ContentResolver;
24666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.content.Context;
25666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.content.Intent;
26666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Bitmap;
27666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Canvas;
28666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Matrix;
29666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Path;
30666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.PointF;
31666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.PorterDuff;
32666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Rect;
33666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.RectF;
34666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.graphics.Region;
35666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.media.FaceDetector;
36666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.net.Uri;
37666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.os.Bundle;
38666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.os.Handler;
39666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.provider.MediaStore;
40666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.util.AttributeSet;
41666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.util.Log;
42666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.view.MotionEvent;
43666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.view.View;
44666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.view.Window;
45666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.view.WindowManager;
46666ea1b28a76aeba74744148b15099254d918671Owen Linimport android.widget.Toast;
47666ea1b28a76aeba74744148b15099254d918671Owen Lin
48666ea1b28a76aeba74744148b15099254d918671Owen Linimport java.io.File;
49666ea1b28a76aeba74744148b15099254d918671Owen Linimport java.io.IOException;
50666ea1b28a76aeba74744148b15099254d918671Owen Linimport java.io.OutputStream;
51666ea1b28a76aeba74744148b15099254d918671Owen Linimport java.util.ArrayList;
52666ea1b28a76aeba74744148b15099254d918671Owen Linimport java.util.concurrent.CountDownLatch;
53666ea1b28a76aeba74744148b15099254d918671Owen Lin
54666ea1b28a76aeba74744148b15099254d918671Owen Lin/**
55666ea1b28a76aeba74744148b15099254d918671Owen Lin * The activity can crop specific region of interest from an image.
56666ea1b28a76aeba74744148b15099254d918671Owen Lin */
57666ea1b28a76aeba74744148b15099254d918671Owen Linpublic class CropImage extends MonitoredActivity {
58666ea1b28a76aeba74744148b15099254d918671Owen Lin    private static final String TAG = "CropImage";
59666ea1b28a76aeba74744148b15099254d918671Owen Lin
60666ea1b28a76aeba74744148b15099254d918671Owen Lin    // These are various options can be specified in the intent.
61666ea1b28a76aeba74744148b15099254d918671Owen Lin    private Bitmap.CompressFormat mOutputFormat =
62666ea1b28a76aeba74744148b15099254d918671Owen Lin            Bitmap.CompressFormat.JPEG; // only used with mSaveUri
63666ea1b28a76aeba74744148b15099254d918671Owen Lin    private Uri mSaveUri = null;
64666ea1b28a76aeba74744148b15099254d918671Owen Lin    private boolean mSetWallpaper = false;
65666ea1b28a76aeba74744148b15099254d918671Owen Lin    private int mAspectX, mAspectY;
66666ea1b28a76aeba74744148b15099254d918671Owen Lin    private boolean mDoFaceDetection = true;
67666ea1b28a76aeba74744148b15099254d918671Owen Lin    private boolean mCircleCrop = false;
68666ea1b28a76aeba74744148b15099254d918671Owen Lin    private final Handler mHandler = new Handler();
69666ea1b28a76aeba74744148b15099254d918671Owen Lin
70666ea1b28a76aeba74744148b15099254d918671Owen Lin    // These options specifiy the output image size and whether we should
71666ea1b28a76aeba74744148b15099254d918671Owen Lin    // scale the output to fit it (or just crop it).
72666ea1b28a76aeba74744148b15099254d918671Owen Lin    private int mOutputX, mOutputY;
73666ea1b28a76aeba74744148b15099254d918671Owen Lin    private boolean mScale;
74666ea1b28a76aeba74744148b15099254d918671Owen Lin    private boolean mScaleUp = true;
75666ea1b28a76aeba74744148b15099254d918671Owen Lin
76666ea1b28a76aeba74744148b15099254d918671Owen Lin    boolean mWaitingToPick; // Whether we are wait the user to pick a face.
77666ea1b28a76aeba74744148b15099254d918671Owen Lin    boolean mSaving;  // Whether the "save" button is already clicked.
78666ea1b28a76aeba74744148b15099254d918671Owen Lin
79666ea1b28a76aeba74744148b15099254d918671Owen Lin    private CropImageView mImageView;
80666ea1b28a76aeba74744148b15099254d918671Owen Lin    private ContentResolver mContentResolver;
81666ea1b28a76aeba74744148b15099254d918671Owen Lin
82666ea1b28a76aeba74744148b15099254d918671Owen Lin    private Bitmap mBitmap;
83666ea1b28a76aeba74744148b15099254d918671Owen Lin    HighlightView mCrop;
84666ea1b28a76aeba74744148b15099254d918671Owen Lin
85666ea1b28a76aeba74744148b15099254d918671Owen Lin    private IImageList mAllImages;
86666ea1b28a76aeba74744148b15099254d918671Owen Lin    private IImage mImage;
87666ea1b28a76aeba74744148b15099254d918671Owen Lin
88666ea1b28a76aeba74744148b15099254d918671Owen Lin    @Override
89666ea1b28a76aeba74744148b15099254d918671Owen Lin    public void onCreate(Bundle icicle) {
90666ea1b28a76aeba74744148b15099254d918671Owen Lin        super.onCreate(icicle);
91666ea1b28a76aeba74744148b15099254d918671Owen Lin        mContentResolver = getContentResolver();
92666ea1b28a76aeba74744148b15099254d918671Owen Lin
93666ea1b28a76aeba74744148b15099254d918671Owen Lin        requestWindowFeature(Window.FEATURE_NO_TITLE);
94666ea1b28a76aeba74744148b15099254d918671Owen Lin        setContentView(R.layout.cropimage);
95666ea1b28a76aeba74744148b15099254d918671Owen Lin
96666ea1b28a76aeba74744148b15099254d918671Owen Lin        mImageView = (CropImageView) findViewById(R.id.image);
97666ea1b28a76aeba74744148b15099254d918671Owen Lin
98666ea1b28a76aeba74744148b15099254d918671Owen Lin        MenuHelper.showStorageToast(this);
99666ea1b28a76aeba74744148b15099254d918671Owen Lin
100666ea1b28a76aeba74744148b15099254d918671Owen Lin        Intent intent = getIntent();
101666ea1b28a76aeba74744148b15099254d918671Owen Lin        Bundle extras = intent.getExtras();
102666ea1b28a76aeba74744148b15099254d918671Owen Lin
103666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (extras != null) {
104666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (extras.getString("circleCrop") != null) {
105666ea1b28a76aeba74744148b15099254d918671Owen Lin                mCircleCrop = true;
106666ea1b28a76aeba74744148b15099254d918671Owen Lin                mAspectX = 1;
107666ea1b28a76aeba74744148b15099254d918671Owen Lin                mAspectY = 1;
108666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
109666ea1b28a76aeba74744148b15099254d918671Owen Lin            mSaveUri = (Uri) extras.getParcelable(MediaStore.EXTRA_OUTPUT);
110666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (mSaveUri != null) {
111666ea1b28a76aeba74744148b15099254d918671Owen Lin                String outputFormatString = extras.getString("outputFormat");
112666ea1b28a76aeba74744148b15099254d918671Owen Lin                if (outputFormatString != null) {
113666ea1b28a76aeba74744148b15099254d918671Owen Lin                    mOutputFormat = Bitmap.CompressFormat.valueOf(
114666ea1b28a76aeba74744148b15099254d918671Owen Lin                            outputFormatString);
115666ea1b28a76aeba74744148b15099254d918671Owen Lin                }
116666ea1b28a76aeba74744148b15099254d918671Owen Lin            } else {
117666ea1b28a76aeba74744148b15099254d918671Owen Lin                mSetWallpaper = extras.getBoolean("setWallpaper");
118666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
119666ea1b28a76aeba74744148b15099254d918671Owen Lin            mBitmap = (Bitmap) extras.getParcelable("data");
120666ea1b28a76aeba74744148b15099254d918671Owen Lin            mAspectX = extras.getInt("aspectX");
121666ea1b28a76aeba74744148b15099254d918671Owen Lin            mAspectY = extras.getInt("aspectY");
122666ea1b28a76aeba74744148b15099254d918671Owen Lin            mOutputX = extras.getInt("outputX");
123666ea1b28a76aeba74744148b15099254d918671Owen Lin            mOutputY = extras.getInt("outputY");
124666ea1b28a76aeba74744148b15099254d918671Owen Lin            mScale = extras.getBoolean("scale", true);
125666ea1b28a76aeba74744148b15099254d918671Owen Lin            mScaleUp = extras.getBoolean("scaleUpIfNeeded", true);
126666ea1b28a76aeba74744148b15099254d918671Owen Lin            mDoFaceDetection = extras.containsKey("noFaceDetection")
127666ea1b28a76aeba74744148b15099254d918671Owen Lin                    ? !extras.getBoolean("noFaceDetection")
128666ea1b28a76aeba74744148b15099254d918671Owen Lin                    : true;
129666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
130666ea1b28a76aeba74744148b15099254d918671Owen Lin
131666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (mBitmap == null) {
132666ea1b28a76aeba74744148b15099254d918671Owen Lin            Uri target = intent.getData();
133666ea1b28a76aeba74744148b15099254d918671Owen Lin            mAllImages = ImageManager.makeImageList(mContentResolver, target,
134666ea1b28a76aeba74744148b15099254d918671Owen Lin                    ImageManager.SORT_ASCENDING);
135666ea1b28a76aeba74744148b15099254d918671Owen Lin            mImage = mAllImages.getImageForUri(target);
136666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (mImage != null) {
137666ea1b28a76aeba74744148b15099254d918671Owen Lin                // Don't read in really large bitmaps. Use the (big) thumbnail
138666ea1b28a76aeba74744148b15099254d918671Owen Lin                // instead.
139666ea1b28a76aeba74744148b15099254d918671Owen Lin                // TODO when saving the resulting bitmap use the
140666ea1b28a76aeba74744148b15099254d918671Owen Lin                // decode/crop/encode api so we don't lose any resolution.
141666ea1b28a76aeba74744148b15099254d918671Owen Lin                mBitmap = mImage.thumbBitmap(IImage.ROTATE_AS_NEEDED);
142666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
143666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
144666ea1b28a76aeba74744148b15099254d918671Owen Lin
145666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (mBitmap == null) {
146666ea1b28a76aeba74744148b15099254d918671Owen Lin            finish();
147666ea1b28a76aeba74744148b15099254d918671Owen Lin            return;
148666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
149666ea1b28a76aeba74744148b15099254d918671Owen Lin
150666ea1b28a76aeba74744148b15099254d918671Owen Lin        // Make UI fullscreen.
151666ea1b28a76aeba74744148b15099254d918671Owen Lin        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
152666ea1b28a76aeba74744148b15099254d918671Owen Lin
153666ea1b28a76aeba74744148b15099254d918671Owen Lin        findViewById(R.id.discard).setOnClickListener(
154666ea1b28a76aeba74744148b15099254d918671Owen Lin                new View.OnClickListener() {
155666ea1b28a76aeba74744148b15099254d918671Owen Lin                    public void onClick(View v) {
156666ea1b28a76aeba74744148b15099254d918671Owen Lin                        setResult(RESULT_CANCELED);
157666ea1b28a76aeba74744148b15099254d918671Owen Lin                        finish();
158666ea1b28a76aeba74744148b15099254d918671Owen Lin                    }
159666ea1b28a76aeba74744148b15099254d918671Owen Lin                });
160666ea1b28a76aeba74744148b15099254d918671Owen Lin
161666ea1b28a76aeba74744148b15099254d918671Owen Lin        findViewById(R.id.save).setOnClickListener(
162666ea1b28a76aeba74744148b15099254d918671Owen Lin                new View.OnClickListener() {
163666ea1b28a76aeba74744148b15099254d918671Owen Lin                    public void onClick(View v) {
164666ea1b28a76aeba74744148b15099254d918671Owen Lin                        onSaveClicked();
165666ea1b28a76aeba74744148b15099254d918671Owen Lin                    }
166666ea1b28a76aeba74744148b15099254d918671Owen Lin                });
167666ea1b28a76aeba74744148b15099254d918671Owen Lin
168666ea1b28a76aeba74744148b15099254d918671Owen Lin        startFaceDetection();
169666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
170666ea1b28a76aeba74744148b15099254d918671Owen Lin
171666ea1b28a76aeba74744148b15099254d918671Owen Lin    private void startFaceDetection() {
172666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (isFinishing()) {
173666ea1b28a76aeba74744148b15099254d918671Owen Lin            return;
174666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
175666ea1b28a76aeba74744148b15099254d918671Owen Lin
176666ea1b28a76aeba74744148b15099254d918671Owen Lin        mImageView.setImageBitmapResetBase(mBitmap, true);
177666ea1b28a76aeba74744148b15099254d918671Owen Lin
178666ea1b28a76aeba74744148b15099254d918671Owen Lin        Util.startBackgroundJob(this, null,
179666ea1b28a76aeba74744148b15099254d918671Owen Lin                getResources().getString(R.string.runningFaceDetection),
180666ea1b28a76aeba74744148b15099254d918671Owen Lin                new Runnable() {
181666ea1b28a76aeba74744148b15099254d918671Owen Lin            public void run() {
182666ea1b28a76aeba74744148b15099254d918671Owen Lin                final CountDownLatch latch = new CountDownLatch(1);
183666ea1b28a76aeba74744148b15099254d918671Owen Lin                final Bitmap b = (mImage != null)
184666ea1b28a76aeba74744148b15099254d918671Owen Lin                        ? mImage.fullSizeBitmap(IImage.UNCONSTRAINED,
185666ea1b28a76aeba74744148b15099254d918671Owen Lin                        1024 * 1024)
186666ea1b28a76aeba74744148b15099254d918671Owen Lin                        : mBitmap;
187666ea1b28a76aeba74744148b15099254d918671Owen Lin                mHandler.post(new Runnable() {
188666ea1b28a76aeba74744148b15099254d918671Owen Lin                    public void run() {
189666ea1b28a76aeba74744148b15099254d918671Owen Lin                        if (b != mBitmap && b != null) {
190666ea1b28a76aeba74744148b15099254d918671Owen Lin                            mImageView.setImageBitmapResetBase(b, true);
191666ea1b28a76aeba74744148b15099254d918671Owen Lin                            mBitmap.recycle();
192666ea1b28a76aeba74744148b15099254d918671Owen Lin                            mBitmap = b;
193666ea1b28a76aeba74744148b15099254d918671Owen Lin                        }
194666ea1b28a76aeba74744148b15099254d918671Owen Lin                        if (mImageView.getScale() == 1F) {
195666ea1b28a76aeba74744148b15099254d918671Owen Lin                            mImageView.center(true, true);
196666ea1b28a76aeba74744148b15099254d918671Owen Lin                        }
197666ea1b28a76aeba74744148b15099254d918671Owen Lin                        latch.countDown();
198666ea1b28a76aeba74744148b15099254d918671Owen Lin                    }
199666ea1b28a76aeba74744148b15099254d918671Owen Lin                });
200666ea1b28a76aeba74744148b15099254d918671Owen Lin                try {
201666ea1b28a76aeba74744148b15099254d918671Owen Lin                    latch.await();
202666ea1b28a76aeba74744148b15099254d918671Owen Lin                } catch (InterruptedException e) {
203666ea1b28a76aeba74744148b15099254d918671Owen Lin                    throw new RuntimeException(e);
204666ea1b28a76aeba74744148b15099254d918671Owen Lin                }
205666ea1b28a76aeba74744148b15099254d918671Owen Lin                mRunFaceDetection.run();
206666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
207666ea1b28a76aeba74744148b15099254d918671Owen Lin        }, mHandler);
208666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
209666ea1b28a76aeba74744148b15099254d918671Owen Lin
210666ea1b28a76aeba74744148b15099254d918671Owen Lin    private void onSaveClicked() {
211666ea1b28a76aeba74744148b15099254d918671Owen Lin        // TODO this code needs to change to use the decode/crop/encode single
212666ea1b28a76aeba74744148b15099254d918671Owen Lin        // step api so that we don't require that the whole (possibly large)
213666ea1b28a76aeba74744148b15099254d918671Owen Lin        // bitmap doesn't have to be read into memory
214666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (mCrop == null) {
215666ea1b28a76aeba74744148b15099254d918671Owen Lin            return;
216666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
217666ea1b28a76aeba74744148b15099254d918671Owen Lin
218666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (mSaving) return;
219666ea1b28a76aeba74744148b15099254d918671Owen Lin        mSaving = true;
220666ea1b28a76aeba74744148b15099254d918671Owen Lin
221666ea1b28a76aeba74744148b15099254d918671Owen Lin        Bitmap croppedImage;
222666ea1b28a76aeba74744148b15099254d918671Owen Lin
223666ea1b28a76aeba74744148b15099254d918671Owen Lin        // If the output is required to a specific size, create an new image
224666ea1b28a76aeba74744148b15099254d918671Owen Lin        // with the cropped image in the center and the extra space filled.
225666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (mOutputX != 0 && mOutputY != 0 && !mScale) {
226666ea1b28a76aeba74744148b15099254d918671Owen Lin            // Don't scale the image but instead fill it so it's the
227666ea1b28a76aeba74744148b15099254d918671Owen Lin            // required dimension
228666ea1b28a76aeba74744148b15099254d918671Owen Lin            croppedImage = Bitmap.createBitmap(mOutputX, mOutputY,
229666ea1b28a76aeba74744148b15099254d918671Owen Lin                    Bitmap.Config.RGB_565);
230666ea1b28a76aeba74744148b15099254d918671Owen Lin            Canvas canvas = new Canvas(croppedImage);
231666ea1b28a76aeba74744148b15099254d918671Owen Lin
232666ea1b28a76aeba74744148b15099254d918671Owen Lin            Rect srcRect = mCrop.getCropRect();
233666ea1b28a76aeba74744148b15099254d918671Owen Lin            Rect dstRect = new Rect(0, 0, mOutputX, mOutputY);
234666ea1b28a76aeba74744148b15099254d918671Owen Lin
235666ea1b28a76aeba74744148b15099254d918671Owen Lin            int dx = (srcRect.width() - dstRect.width()) / 2;
236666ea1b28a76aeba74744148b15099254d918671Owen Lin            int dy = (srcRect.height() - dstRect.height()) / 2;
237666ea1b28a76aeba74744148b15099254d918671Owen Lin
238666ea1b28a76aeba74744148b15099254d918671Owen Lin            // If the srcRect is too big, use the center part of it.
239666ea1b28a76aeba74744148b15099254d918671Owen Lin            srcRect.inset(Math.max(0, dx), Math.max(0, dy));
240666ea1b28a76aeba74744148b15099254d918671Owen Lin
241666ea1b28a76aeba74744148b15099254d918671Owen Lin            // If the dstRect is too big, use the center part of it.
242666ea1b28a76aeba74744148b15099254d918671Owen Lin            dstRect.inset(Math.max(0, -dx), Math.max(0, -dy));
243666ea1b28a76aeba74744148b15099254d918671Owen Lin
244666ea1b28a76aeba74744148b15099254d918671Owen Lin            // Draw the cropped bitmap in the center
245666ea1b28a76aeba74744148b15099254d918671Owen Lin            canvas.drawBitmap(mBitmap, srcRect, dstRect, null);
246666ea1b28a76aeba74744148b15099254d918671Owen Lin
247666ea1b28a76aeba74744148b15099254d918671Owen Lin            // Release bitmap memory as soon as possible
248666ea1b28a76aeba74744148b15099254d918671Owen Lin            mImageView.clear();
249666ea1b28a76aeba74744148b15099254d918671Owen Lin            mBitmap.recycle();
250666ea1b28a76aeba74744148b15099254d918671Owen Lin        } else {
251666ea1b28a76aeba74744148b15099254d918671Owen Lin            Rect r = mCrop.getCropRect();
252666ea1b28a76aeba74744148b15099254d918671Owen Lin
253666ea1b28a76aeba74744148b15099254d918671Owen Lin            int width = r.width();
254666ea1b28a76aeba74744148b15099254d918671Owen Lin            int height = r.height();
255666ea1b28a76aeba74744148b15099254d918671Owen Lin
256666ea1b28a76aeba74744148b15099254d918671Owen Lin            // If we are circle cropping, we want alpha channel, which is the
257666ea1b28a76aeba74744148b15099254d918671Owen Lin            // third param here.
258666ea1b28a76aeba74744148b15099254d918671Owen Lin            croppedImage = Bitmap.createBitmap(width, height,
259666ea1b28a76aeba74744148b15099254d918671Owen Lin                    mCircleCrop
260666ea1b28a76aeba74744148b15099254d918671Owen Lin                    ? Bitmap.Config.ARGB_8888
261666ea1b28a76aeba74744148b15099254d918671Owen Lin                    : Bitmap.Config.RGB_565);
262666ea1b28a76aeba74744148b15099254d918671Owen Lin
263666ea1b28a76aeba74744148b15099254d918671Owen Lin            Canvas canvas = new Canvas(croppedImage);
264666ea1b28a76aeba74744148b15099254d918671Owen Lin            Rect dstRect = new Rect(0, 0, width, height);
265666ea1b28a76aeba74744148b15099254d918671Owen Lin            canvas.drawBitmap(mBitmap, r, dstRect, null);
266666ea1b28a76aeba74744148b15099254d918671Owen Lin
267666ea1b28a76aeba74744148b15099254d918671Owen Lin            // Release bitmap memory as soon as possible
268666ea1b28a76aeba74744148b15099254d918671Owen Lin            mImageView.clear();
269666ea1b28a76aeba74744148b15099254d918671Owen Lin            mBitmap.recycle();
270666ea1b28a76aeba74744148b15099254d918671Owen Lin
271666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (mCircleCrop) {
272666ea1b28a76aeba74744148b15099254d918671Owen Lin                // OK, so what's all this about?
273666ea1b28a76aeba74744148b15099254d918671Owen Lin                // Bitmaps are inherently rectangular but we want to return
274666ea1b28a76aeba74744148b15099254d918671Owen Lin                // something that's basically a circle.  So we fill in the
275666ea1b28a76aeba74744148b15099254d918671Owen Lin                // area around the circle with alpha.  Note the all important
276666ea1b28a76aeba74744148b15099254d918671Owen Lin                // PortDuff.Mode.CLEAR.
277666ea1b28a76aeba74744148b15099254d918671Owen Lin                Canvas c = new Canvas(croppedImage);
278666ea1b28a76aeba74744148b15099254d918671Owen Lin                Path p = new Path();
279666ea1b28a76aeba74744148b15099254d918671Owen Lin                p.addCircle(width / 2F, height / 2F, width / 2F,
280666ea1b28a76aeba74744148b15099254d918671Owen Lin                        Path.Direction.CW);
281666ea1b28a76aeba74744148b15099254d918671Owen Lin                c.clipPath(p, Region.Op.DIFFERENCE);
282666ea1b28a76aeba74744148b15099254d918671Owen Lin                c.drawColor(0x00000000, PorterDuff.Mode.CLEAR);
283666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
284666ea1b28a76aeba74744148b15099254d918671Owen Lin
285666ea1b28a76aeba74744148b15099254d918671Owen Lin            // If the required dimension is specified, scale the image.
286666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (mOutputX != 0 && mOutputY != 0 && mScale) {
287666ea1b28a76aeba74744148b15099254d918671Owen Lin                croppedImage = Util.transform(new Matrix(), croppedImage,
288666ea1b28a76aeba74744148b15099254d918671Owen Lin                        mOutputX, mOutputY, mScaleUp, Util.RECYCLE_INPUT);
289666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
290666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
291666ea1b28a76aeba74744148b15099254d918671Owen Lin
292666ea1b28a76aeba74744148b15099254d918671Owen Lin        mImageView.setImageBitmapResetBase(croppedImage, true);
293666ea1b28a76aeba74744148b15099254d918671Owen Lin        mImageView.center(true, true);
294666ea1b28a76aeba74744148b15099254d918671Owen Lin        mImageView.mHighlightViews.clear();
295666ea1b28a76aeba74744148b15099254d918671Owen Lin
296666ea1b28a76aeba74744148b15099254d918671Owen Lin        // Return the cropped image directly or save it to the specified URI.
297666ea1b28a76aeba74744148b15099254d918671Owen Lin        Bundle myExtras = getIntent().getExtras();
298666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (myExtras != null && (myExtras.getParcelable("data") != null
299666ea1b28a76aeba74744148b15099254d918671Owen Lin                || myExtras.getBoolean("return-data"))) {
300666ea1b28a76aeba74744148b15099254d918671Owen Lin            Bundle extras = new Bundle();
301666ea1b28a76aeba74744148b15099254d918671Owen Lin            extras.putParcelable("data", croppedImage);
302666ea1b28a76aeba74744148b15099254d918671Owen Lin            setResult(RESULT_OK,
303666ea1b28a76aeba74744148b15099254d918671Owen Lin                    (new Intent()).setAction("inline-data").putExtras(extras));
304666ea1b28a76aeba74744148b15099254d918671Owen Lin            finish();
305666ea1b28a76aeba74744148b15099254d918671Owen Lin        } else {
306666ea1b28a76aeba74744148b15099254d918671Owen Lin            final Bitmap b = croppedImage;
307666ea1b28a76aeba74744148b15099254d918671Owen Lin            final int msdId = mSetWallpaper
308666ea1b28a76aeba74744148b15099254d918671Owen Lin                    ? R.string.wallpaper
309666ea1b28a76aeba74744148b15099254d918671Owen Lin                    : R.string.savingImage;
310666ea1b28a76aeba74744148b15099254d918671Owen Lin            Util.startBackgroundJob(this, null,
311666ea1b28a76aeba74744148b15099254d918671Owen Lin                    getResources().getString(msdId),
312666ea1b28a76aeba74744148b15099254d918671Owen Lin                    new Runnable() {
313666ea1b28a76aeba74744148b15099254d918671Owen Lin                public void run() {
314666ea1b28a76aeba74744148b15099254d918671Owen Lin                    saveOutput(b);
315666ea1b28a76aeba74744148b15099254d918671Owen Lin                }
316666ea1b28a76aeba74744148b15099254d918671Owen Lin            }, mHandler);
317666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
318666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
319666ea1b28a76aeba74744148b15099254d918671Owen Lin
320666ea1b28a76aeba74744148b15099254d918671Owen Lin    private void saveOutput(Bitmap croppedImage) {
321666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (mSaveUri != null) {
322666ea1b28a76aeba74744148b15099254d918671Owen Lin            OutputStream outputStream = null;
323666ea1b28a76aeba74744148b15099254d918671Owen Lin            try {
324666ea1b28a76aeba74744148b15099254d918671Owen Lin                outputStream = mContentResolver.openOutputStream(mSaveUri);
325666ea1b28a76aeba74744148b15099254d918671Owen Lin                if (outputStream != null) {
326666ea1b28a76aeba74744148b15099254d918671Owen Lin                    croppedImage.compress(mOutputFormat, 75, outputStream);
327666ea1b28a76aeba74744148b15099254d918671Owen Lin                }
328666ea1b28a76aeba74744148b15099254d918671Owen Lin            } catch (IOException ex) {
329666ea1b28a76aeba74744148b15099254d918671Owen Lin                // TODO: report error to caller
330666ea1b28a76aeba74744148b15099254d918671Owen Lin                Log.e(TAG, "Cannot open file: " + mSaveUri, ex);
331666ea1b28a76aeba74744148b15099254d918671Owen Lin            } finally {
332666ea1b28a76aeba74744148b15099254d918671Owen Lin                Util.closeSilently(outputStream);
333666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
334666ea1b28a76aeba74744148b15099254d918671Owen Lin            Bundle extras = new Bundle();
335666ea1b28a76aeba74744148b15099254d918671Owen Lin            setResult(RESULT_OK, new Intent(mSaveUri.toString())
336666ea1b28a76aeba74744148b15099254d918671Owen Lin                    .putExtras(extras));
337666ea1b28a76aeba74744148b15099254d918671Owen Lin        } else if (mSetWallpaper) {
338666ea1b28a76aeba74744148b15099254d918671Owen Lin            try {
339666ea1b28a76aeba74744148b15099254d918671Owen Lin                WallpaperManager.getInstance(this).setBitmap(croppedImage);
340666ea1b28a76aeba74744148b15099254d918671Owen Lin                setResult(RESULT_OK);
341666ea1b28a76aeba74744148b15099254d918671Owen Lin            } catch (IOException e) {
342666ea1b28a76aeba74744148b15099254d918671Owen Lin                Log.e(TAG, "Failed to set wallpaper.", e);
343666ea1b28a76aeba74744148b15099254d918671Owen Lin                setResult(RESULT_CANCELED);
344666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
345666ea1b28a76aeba74744148b15099254d918671Owen Lin        } else {
346666ea1b28a76aeba74744148b15099254d918671Owen Lin            Bundle extras = new Bundle();
347666ea1b28a76aeba74744148b15099254d918671Owen Lin            extras.putString("rect", mCrop.getCropRect().toString());
348666ea1b28a76aeba74744148b15099254d918671Owen Lin
349666ea1b28a76aeba74744148b15099254d918671Owen Lin            File oldPath = new File(mImage.getDataPath());
350666ea1b28a76aeba74744148b15099254d918671Owen Lin            File directory = new File(oldPath.getParent());
351666ea1b28a76aeba74744148b15099254d918671Owen Lin
352666ea1b28a76aeba74744148b15099254d918671Owen Lin            int x = 0;
353666ea1b28a76aeba74744148b15099254d918671Owen Lin            String fileName = oldPath.getName();
354666ea1b28a76aeba74744148b15099254d918671Owen Lin            fileName = fileName.substring(0, fileName.lastIndexOf("."));
355666ea1b28a76aeba74744148b15099254d918671Owen Lin
356666ea1b28a76aeba74744148b15099254d918671Owen Lin            // Try file-1.jpg, file-2.jpg, ... until we find a filename which
357666ea1b28a76aeba74744148b15099254d918671Owen Lin            // does not exist yet.
358666ea1b28a76aeba74744148b15099254d918671Owen Lin            while (true) {
359666ea1b28a76aeba74744148b15099254d918671Owen Lin                x += 1;
360666ea1b28a76aeba74744148b15099254d918671Owen Lin                String candidate = directory.toString()
361666ea1b28a76aeba74744148b15099254d918671Owen Lin                        + "/" + fileName + "-" + x + ".jpg";
362666ea1b28a76aeba74744148b15099254d918671Owen Lin                boolean exists = (new File(candidate)).exists();
363666ea1b28a76aeba74744148b15099254d918671Owen Lin                if (!exists) {
364666ea1b28a76aeba74744148b15099254d918671Owen Lin                    break;
365666ea1b28a76aeba74744148b15099254d918671Owen Lin                }
366666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
367666ea1b28a76aeba74744148b15099254d918671Owen Lin
368666ea1b28a76aeba74744148b15099254d918671Owen Lin            try {
369666ea1b28a76aeba74744148b15099254d918671Owen Lin                int[] degree = new int[1];
370666ea1b28a76aeba74744148b15099254d918671Owen Lin                Uri newUri = ImageManager.addImage(
371666ea1b28a76aeba74744148b15099254d918671Owen Lin                        mContentResolver,
372666ea1b28a76aeba74744148b15099254d918671Owen Lin                        mImage.getTitle(),
373666ea1b28a76aeba74744148b15099254d918671Owen Lin                        mImage.getDateTaken(),
374666ea1b28a76aeba74744148b15099254d918671Owen Lin                        null,    // TODO this null is going to cause us to lose
375666ea1b28a76aeba74744148b15099254d918671Owen Lin                                 // the location (gps).
376666ea1b28a76aeba74744148b15099254d918671Owen Lin                        directory.toString(), fileName + "-" + x + ".jpg",
377666ea1b28a76aeba74744148b15099254d918671Owen Lin                        croppedImage, null,
378666ea1b28a76aeba74744148b15099254d918671Owen Lin                        degree);
379666ea1b28a76aeba74744148b15099254d918671Owen Lin
380666ea1b28a76aeba74744148b15099254d918671Owen Lin                setResult(RESULT_OK, new Intent()
381666ea1b28a76aeba74744148b15099254d918671Owen Lin                        .setAction(newUri.toString())
382666ea1b28a76aeba74744148b15099254d918671Owen Lin                        .putExtras(extras));
383666ea1b28a76aeba74744148b15099254d918671Owen Lin            } catch (Exception ex) {
384666ea1b28a76aeba74744148b15099254d918671Owen Lin                // basically ignore this or put up
385666ea1b28a76aeba74744148b15099254d918671Owen Lin                // some ui saying we failed
386666ea1b28a76aeba74744148b15099254d918671Owen Lin                Log.e(TAG, "store image fail, continue anyway", ex);
387666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
388666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
389666ea1b28a76aeba74744148b15099254d918671Owen Lin
390666ea1b28a76aeba74744148b15099254d918671Owen Lin        final Bitmap b = croppedImage;
391666ea1b28a76aeba74744148b15099254d918671Owen Lin        mHandler.post(new Runnable() {
392666ea1b28a76aeba74744148b15099254d918671Owen Lin            public void run() {
393666ea1b28a76aeba74744148b15099254d918671Owen Lin                mImageView.clear();
394666ea1b28a76aeba74744148b15099254d918671Owen Lin                b.recycle();
395666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
396666ea1b28a76aeba74744148b15099254d918671Owen Lin        });
397666ea1b28a76aeba74744148b15099254d918671Owen Lin
398666ea1b28a76aeba74744148b15099254d918671Owen Lin        finish();
399666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
400666ea1b28a76aeba74744148b15099254d918671Owen Lin
401666ea1b28a76aeba74744148b15099254d918671Owen Lin    @Override
402666ea1b28a76aeba74744148b15099254d918671Owen Lin    protected void onPause() {
403666ea1b28a76aeba74744148b15099254d918671Owen Lin        super.onPause();
404666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
405666ea1b28a76aeba74744148b15099254d918671Owen Lin
406666ea1b28a76aeba74744148b15099254d918671Owen Lin    @Override
407666ea1b28a76aeba74744148b15099254d918671Owen Lin    protected void onDestroy() {
408666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (mAllImages != null) {
409666ea1b28a76aeba74744148b15099254d918671Owen Lin            mAllImages.close();
410666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
411666ea1b28a76aeba74744148b15099254d918671Owen Lin        super.onDestroy();
412666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
413666ea1b28a76aeba74744148b15099254d918671Owen Lin
414666ea1b28a76aeba74744148b15099254d918671Owen Lin    Runnable mRunFaceDetection = new Runnable() {
415666ea1b28a76aeba74744148b15099254d918671Owen Lin        @SuppressWarnings("hiding")
416666ea1b28a76aeba74744148b15099254d918671Owen Lin        float mScale = 1F;
417666ea1b28a76aeba74744148b15099254d918671Owen Lin        Matrix mImageMatrix;
418666ea1b28a76aeba74744148b15099254d918671Owen Lin        FaceDetector.Face[] mFaces = new FaceDetector.Face[3];
419666ea1b28a76aeba74744148b15099254d918671Owen Lin        int mNumFaces;
420666ea1b28a76aeba74744148b15099254d918671Owen Lin
421666ea1b28a76aeba74744148b15099254d918671Owen Lin        // For each face, we create a HightlightView for it.
422666ea1b28a76aeba74744148b15099254d918671Owen Lin        private void handleFace(FaceDetector.Face f) {
423666ea1b28a76aeba74744148b15099254d918671Owen Lin            PointF midPoint = new PointF();
424666ea1b28a76aeba74744148b15099254d918671Owen Lin
425666ea1b28a76aeba74744148b15099254d918671Owen Lin            int r = ((int) (f.eyesDistance() * mScale)) * 2;
426666ea1b28a76aeba74744148b15099254d918671Owen Lin            f.getMidPoint(midPoint);
427666ea1b28a76aeba74744148b15099254d918671Owen Lin            midPoint.x *= mScale;
428666ea1b28a76aeba74744148b15099254d918671Owen Lin            midPoint.y *= mScale;
429666ea1b28a76aeba74744148b15099254d918671Owen Lin
430666ea1b28a76aeba74744148b15099254d918671Owen Lin            int midX = (int) midPoint.x;
431666ea1b28a76aeba74744148b15099254d918671Owen Lin            int midY = (int) midPoint.y;
432666ea1b28a76aeba74744148b15099254d918671Owen Lin
433666ea1b28a76aeba74744148b15099254d918671Owen Lin            HighlightView hv = new HighlightView(mImageView);
434666ea1b28a76aeba74744148b15099254d918671Owen Lin
435666ea1b28a76aeba74744148b15099254d918671Owen Lin            int width = mBitmap.getWidth();
436666ea1b28a76aeba74744148b15099254d918671Owen Lin            int height = mBitmap.getHeight();
437666ea1b28a76aeba74744148b15099254d918671Owen Lin
438666ea1b28a76aeba74744148b15099254d918671Owen Lin            Rect imageRect = new Rect(0, 0, width, height);
439666ea1b28a76aeba74744148b15099254d918671Owen Lin
440666ea1b28a76aeba74744148b15099254d918671Owen Lin            RectF faceRect = new RectF(midX, midY, midX, midY);
441666ea1b28a76aeba74744148b15099254d918671Owen Lin            faceRect.inset(-r, -r);
442666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (faceRect.left < 0) {
443666ea1b28a76aeba74744148b15099254d918671Owen Lin                faceRect.inset(-faceRect.left, -faceRect.left);
444666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
445666ea1b28a76aeba74744148b15099254d918671Owen Lin
446666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (faceRect.top < 0) {
447666ea1b28a76aeba74744148b15099254d918671Owen Lin                faceRect.inset(-faceRect.top, -faceRect.top);
448666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
449666ea1b28a76aeba74744148b15099254d918671Owen Lin
450666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (faceRect.right > imageRect.right) {
451666ea1b28a76aeba74744148b15099254d918671Owen Lin                faceRect.inset(faceRect.right - imageRect.right,
452666ea1b28a76aeba74744148b15099254d918671Owen Lin                               faceRect.right - imageRect.right);
453666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
454666ea1b28a76aeba74744148b15099254d918671Owen Lin
455666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (faceRect.bottom > imageRect.bottom) {
456666ea1b28a76aeba74744148b15099254d918671Owen Lin                faceRect.inset(faceRect.bottom - imageRect.bottom,
457666ea1b28a76aeba74744148b15099254d918671Owen Lin                               faceRect.bottom - imageRect.bottom);
458666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
459666ea1b28a76aeba74744148b15099254d918671Owen Lin
460666ea1b28a76aeba74744148b15099254d918671Owen Lin            hv.setup(mImageMatrix, imageRect, faceRect, mCircleCrop,
461666ea1b28a76aeba74744148b15099254d918671Owen Lin                     mAspectX != 0 && mAspectY != 0);
462666ea1b28a76aeba74744148b15099254d918671Owen Lin
463666ea1b28a76aeba74744148b15099254d918671Owen Lin            mImageView.add(hv);
464666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
465666ea1b28a76aeba74744148b15099254d918671Owen Lin
466666ea1b28a76aeba74744148b15099254d918671Owen Lin        // Create a default HightlightView if we found no face in the picture.
467666ea1b28a76aeba74744148b15099254d918671Owen Lin        private void makeDefault() {
468666ea1b28a76aeba74744148b15099254d918671Owen Lin            HighlightView hv = new HighlightView(mImageView);
469666ea1b28a76aeba74744148b15099254d918671Owen Lin
470666ea1b28a76aeba74744148b15099254d918671Owen Lin            int width = mBitmap.getWidth();
471666ea1b28a76aeba74744148b15099254d918671Owen Lin            int height = mBitmap.getHeight();
472666ea1b28a76aeba74744148b15099254d918671Owen Lin
473666ea1b28a76aeba74744148b15099254d918671Owen Lin            Rect imageRect = new Rect(0, 0, width, height);
474666ea1b28a76aeba74744148b15099254d918671Owen Lin
475666ea1b28a76aeba74744148b15099254d918671Owen Lin            // make the default size about 4/5 of the width or height
476666ea1b28a76aeba74744148b15099254d918671Owen Lin            int cropWidth = Math.min(width, height) * 4 / 5;
477666ea1b28a76aeba74744148b15099254d918671Owen Lin            int cropHeight = cropWidth;
478666ea1b28a76aeba74744148b15099254d918671Owen Lin
479666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (mAspectX != 0 && mAspectY != 0) {
480666ea1b28a76aeba74744148b15099254d918671Owen Lin                if (mAspectX > mAspectY) {
481666ea1b28a76aeba74744148b15099254d918671Owen Lin                    cropHeight = cropWidth * mAspectY / mAspectX;
482666ea1b28a76aeba74744148b15099254d918671Owen Lin                } else {
483666ea1b28a76aeba74744148b15099254d918671Owen Lin                    cropWidth = cropHeight * mAspectX / mAspectY;
484666ea1b28a76aeba74744148b15099254d918671Owen Lin                }
485666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
486666ea1b28a76aeba74744148b15099254d918671Owen Lin
487666ea1b28a76aeba74744148b15099254d918671Owen Lin            int x = (width - cropWidth) / 2;
488666ea1b28a76aeba74744148b15099254d918671Owen Lin            int y = (height - cropHeight) / 2;
489666ea1b28a76aeba74744148b15099254d918671Owen Lin
490666ea1b28a76aeba74744148b15099254d918671Owen Lin            RectF cropRect = new RectF(x, y, x + cropWidth, y + cropHeight);
491666ea1b28a76aeba74744148b15099254d918671Owen Lin            hv.setup(mImageMatrix, imageRect, cropRect, mCircleCrop,
492666ea1b28a76aeba74744148b15099254d918671Owen Lin                     mAspectX != 0 && mAspectY != 0);
493666ea1b28a76aeba74744148b15099254d918671Owen Lin            mImageView.add(hv);
494666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
495666ea1b28a76aeba74744148b15099254d918671Owen Lin
496666ea1b28a76aeba74744148b15099254d918671Owen Lin        // Scale the image down for faster face detection.
497666ea1b28a76aeba74744148b15099254d918671Owen Lin        private Bitmap prepareBitmap() {
498666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (mBitmap == null) {
499666ea1b28a76aeba74744148b15099254d918671Owen Lin                return null;
500666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
501666ea1b28a76aeba74744148b15099254d918671Owen Lin
502666ea1b28a76aeba74744148b15099254d918671Owen Lin            // 256 pixels wide is enough.
503666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (mBitmap.getWidth() > 256) {
504666ea1b28a76aeba74744148b15099254d918671Owen Lin                mScale = 256.0F / mBitmap.getWidth();
505666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
506666ea1b28a76aeba74744148b15099254d918671Owen Lin            Matrix matrix = new Matrix();
507666ea1b28a76aeba74744148b15099254d918671Owen Lin            matrix.setScale(mScale, mScale);
508666ea1b28a76aeba74744148b15099254d918671Owen Lin            Bitmap faceBitmap = Bitmap.createBitmap(mBitmap, 0, 0, mBitmap
509666ea1b28a76aeba74744148b15099254d918671Owen Lin                    .getWidth(), mBitmap.getHeight(), matrix, true);
510666ea1b28a76aeba74744148b15099254d918671Owen Lin            return faceBitmap;
511666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
512666ea1b28a76aeba74744148b15099254d918671Owen Lin
513666ea1b28a76aeba74744148b15099254d918671Owen Lin        public void run() {
514666ea1b28a76aeba74744148b15099254d918671Owen Lin            mImageMatrix = mImageView.getImageMatrix();
515666ea1b28a76aeba74744148b15099254d918671Owen Lin            Bitmap faceBitmap = prepareBitmap();
516666ea1b28a76aeba74744148b15099254d918671Owen Lin
517666ea1b28a76aeba74744148b15099254d918671Owen Lin            mScale = 1.0F / mScale;
518666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (faceBitmap != null && mDoFaceDetection) {
519666ea1b28a76aeba74744148b15099254d918671Owen Lin                FaceDetector detector = new FaceDetector(faceBitmap.getWidth(),
520666ea1b28a76aeba74744148b15099254d918671Owen Lin                        faceBitmap.getHeight(), mFaces.length);
521666ea1b28a76aeba74744148b15099254d918671Owen Lin                mNumFaces = detector.findFaces(faceBitmap, mFaces);
522666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
523666ea1b28a76aeba74744148b15099254d918671Owen Lin
524666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (faceBitmap != null && faceBitmap != mBitmap) {
525666ea1b28a76aeba74744148b15099254d918671Owen Lin                faceBitmap.recycle();
526666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
527666ea1b28a76aeba74744148b15099254d918671Owen Lin
528666ea1b28a76aeba74744148b15099254d918671Owen Lin            mHandler.post(new Runnable() {
529666ea1b28a76aeba74744148b15099254d918671Owen Lin                public void run() {
530666ea1b28a76aeba74744148b15099254d918671Owen Lin                    mWaitingToPick = mNumFaces > 1;
531666ea1b28a76aeba74744148b15099254d918671Owen Lin                    if (mNumFaces > 0) {
532666ea1b28a76aeba74744148b15099254d918671Owen Lin                        for (int i = 0; i < mNumFaces; i++) {
533666ea1b28a76aeba74744148b15099254d918671Owen Lin                            handleFace(mFaces[i]);
534666ea1b28a76aeba74744148b15099254d918671Owen Lin                        }
535666ea1b28a76aeba74744148b15099254d918671Owen Lin                    } else {
536666ea1b28a76aeba74744148b15099254d918671Owen Lin                        makeDefault();
537666ea1b28a76aeba74744148b15099254d918671Owen Lin                    }
538666ea1b28a76aeba74744148b15099254d918671Owen Lin                    mImageView.invalidate();
539666ea1b28a76aeba74744148b15099254d918671Owen Lin                    if (mImageView.mHighlightViews.size() == 1) {
540666ea1b28a76aeba74744148b15099254d918671Owen Lin                        mCrop = mImageView.mHighlightViews.get(0);
541666ea1b28a76aeba74744148b15099254d918671Owen Lin                        mCrop.setFocus(true);
542666ea1b28a76aeba74744148b15099254d918671Owen Lin                    }
543666ea1b28a76aeba74744148b15099254d918671Owen Lin
544666ea1b28a76aeba74744148b15099254d918671Owen Lin                    if (mNumFaces > 1) {
545666ea1b28a76aeba74744148b15099254d918671Owen Lin                        Toast t = Toast.makeText(CropImage.this,
546666ea1b28a76aeba74744148b15099254d918671Owen Lin                                R.string.multiface_crop_help,
547666ea1b28a76aeba74744148b15099254d918671Owen Lin                                Toast.LENGTH_SHORT);
548666ea1b28a76aeba74744148b15099254d918671Owen Lin                        t.show();
549666ea1b28a76aeba74744148b15099254d918671Owen Lin                    }
550666ea1b28a76aeba74744148b15099254d918671Owen Lin                }
551666ea1b28a76aeba74744148b15099254d918671Owen Lin            });
552666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
553666ea1b28a76aeba74744148b15099254d918671Owen Lin    };
554666ea1b28a76aeba74744148b15099254d918671Owen Lin}
555666ea1b28a76aeba74744148b15099254d918671Owen Lin
556666ea1b28a76aeba74744148b15099254d918671Owen Linclass CropImageView extends ImageViewTouchBase {
557666ea1b28a76aeba74744148b15099254d918671Owen Lin    ArrayList<HighlightView> mHighlightViews = new ArrayList<HighlightView>();
558666ea1b28a76aeba74744148b15099254d918671Owen Lin    HighlightView mMotionHighlightView = null;
559666ea1b28a76aeba74744148b15099254d918671Owen Lin    float mLastX, mLastY;
560666ea1b28a76aeba74744148b15099254d918671Owen Lin    int mMotionEdge;
561666ea1b28a76aeba74744148b15099254d918671Owen Lin
562666ea1b28a76aeba74744148b15099254d918671Owen Lin    @Override
563666ea1b28a76aeba74744148b15099254d918671Owen Lin    protected void onLayout(boolean changed, int left, int top,
564666ea1b28a76aeba74744148b15099254d918671Owen Lin                            int right, int bottom) {
565666ea1b28a76aeba74744148b15099254d918671Owen Lin        super.onLayout(changed, left, top, right, bottom);
566666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (mBitmapDisplayed.getBitmap() != null) {
567666ea1b28a76aeba74744148b15099254d918671Owen Lin            for (HighlightView hv : mHighlightViews) {
568666ea1b28a76aeba74744148b15099254d918671Owen Lin                hv.mMatrix.set(getImageMatrix());
569666ea1b28a76aeba74744148b15099254d918671Owen Lin                hv.invalidate();
570666ea1b28a76aeba74744148b15099254d918671Owen Lin                if (hv.mIsFocused) {
571666ea1b28a76aeba74744148b15099254d918671Owen Lin                    centerBasedOnHighlightView(hv);
572666ea1b28a76aeba74744148b15099254d918671Owen Lin                }
573666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
574666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
575666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
576666ea1b28a76aeba74744148b15099254d918671Owen Lin
577666ea1b28a76aeba74744148b15099254d918671Owen Lin    public CropImageView(Context context, AttributeSet attrs) {
578666ea1b28a76aeba74744148b15099254d918671Owen Lin        super(context, attrs);
579666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
580666ea1b28a76aeba74744148b15099254d918671Owen Lin
581666ea1b28a76aeba74744148b15099254d918671Owen Lin    @Override
582666ea1b28a76aeba74744148b15099254d918671Owen Lin    protected void zoomTo(float scale, float centerX, float centerY) {
583666ea1b28a76aeba74744148b15099254d918671Owen Lin        super.zoomTo(scale, centerX, centerY);
584666ea1b28a76aeba74744148b15099254d918671Owen Lin        for (HighlightView hv : mHighlightViews) {
585666ea1b28a76aeba74744148b15099254d918671Owen Lin            hv.mMatrix.set(getImageMatrix());
586666ea1b28a76aeba74744148b15099254d918671Owen Lin            hv.invalidate();
587666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
588666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
589666ea1b28a76aeba74744148b15099254d918671Owen Lin
590666ea1b28a76aeba74744148b15099254d918671Owen Lin    @Override
591666ea1b28a76aeba74744148b15099254d918671Owen Lin    protected void zoomIn() {
592666ea1b28a76aeba74744148b15099254d918671Owen Lin        super.zoomIn();
593666ea1b28a76aeba74744148b15099254d918671Owen Lin        for (HighlightView hv : mHighlightViews) {
594666ea1b28a76aeba74744148b15099254d918671Owen Lin            hv.mMatrix.set(getImageMatrix());
595666ea1b28a76aeba74744148b15099254d918671Owen Lin            hv.invalidate();
596666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
597666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
598666ea1b28a76aeba74744148b15099254d918671Owen Lin
599666ea1b28a76aeba74744148b15099254d918671Owen Lin    @Override
600666ea1b28a76aeba74744148b15099254d918671Owen Lin    protected void zoomOut() {
601666ea1b28a76aeba74744148b15099254d918671Owen Lin        super.zoomOut();
602666ea1b28a76aeba74744148b15099254d918671Owen Lin        for (HighlightView hv : mHighlightViews) {
603666ea1b28a76aeba74744148b15099254d918671Owen Lin            hv.mMatrix.set(getImageMatrix());
604666ea1b28a76aeba74744148b15099254d918671Owen Lin            hv.invalidate();
605666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
606666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
607666ea1b28a76aeba74744148b15099254d918671Owen Lin
608666ea1b28a76aeba74744148b15099254d918671Owen Lin    @Override
609666ea1b28a76aeba74744148b15099254d918671Owen Lin    protected void postTranslate(float deltaX, float deltaY) {
610666ea1b28a76aeba74744148b15099254d918671Owen Lin        super.postTranslate(deltaX, deltaY);
611666ea1b28a76aeba74744148b15099254d918671Owen Lin        for (int i = 0; i < mHighlightViews.size(); i++) {
612666ea1b28a76aeba74744148b15099254d918671Owen Lin            HighlightView hv = mHighlightViews.get(i);
613666ea1b28a76aeba74744148b15099254d918671Owen Lin            hv.mMatrix.postTranslate(deltaX, deltaY);
614666ea1b28a76aeba74744148b15099254d918671Owen Lin            hv.invalidate();
615666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
616666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
617666ea1b28a76aeba74744148b15099254d918671Owen Lin
618666ea1b28a76aeba74744148b15099254d918671Owen Lin    // According to the event's position, change the focus to the first
619666ea1b28a76aeba74744148b15099254d918671Owen Lin    // hitting cropping rectangle.
620666ea1b28a76aeba74744148b15099254d918671Owen Lin    private void recomputeFocus(MotionEvent event) {
621666ea1b28a76aeba74744148b15099254d918671Owen Lin        for (int i = 0; i < mHighlightViews.size(); i++) {
622666ea1b28a76aeba74744148b15099254d918671Owen Lin            HighlightView hv = mHighlightViews.get(i);
623666ea1b28a76aeba74744148b15099254d918671Owen Lin            hv.setFocus(false);
624666ea1b28a76aeba74744148b15099254d918671Owen Lin            hv.invalidate();
625666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
626666ea1b28a76aeba74744148b15099254d918671Owen Lin
627666ea1b28a76aeba74744148b15099254d918671Owen Lin        for (int i = 0; i < mHighlightViews.size(); i++) {
628666ea1b28a76aeba74744148b15099254d918671Owen Lin            HighlightView hv = mHighlightViews.get(i);
629666ea1b28a76aeba74744148b15099254d918671Owen Lin            int edge = hv.getHit(event.getX(), event.getY());
630666ea1b28a76aeba74744148b15099254d918671Owen Lin            if (edge != HighlightView.GROW_NONE) {
631666ea1b28a76aeba74744148b15099254d918671Owen Lin                if (!hv.hasFocus()) {
632666ea1b28a76aeba74744148b15099254d918671Owen Lin                    hv.setFocus(true);
633666ea1b28a76aeba74744148b15099254d918671Owen Lin                    hv.invalidate();
634666ea1b28a76aeba74744148b15099254d918671Owen Lin                }
635666ea1b28a76aeba74744148b15099254d918671Owen Lin                break;
636666ea1b28a76aeba74744148b15099254d918671Owen Lin            }
637666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
638666ea1b28a76aeba74744148b15099254d918671Owen Lin        invalidate();
639666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
640666ea1b28a76aeba74744148b15099254d918671Owen Lin
641666ea1b28a76aeba74744148b15099254d918671Owen Lin    @Override
642666ea1b28a76aeba74744148b15099254d918671Owen Lin    public boolean onTouchEvent(MotionEvent event) {
643666ea1b28a76aeba74744148b15099254d918671Owen Lin        CropImage cropImage = (CropImage) mContext;
644666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (cropImage.mSaving) {
645666ea1b28a76aeba74744148b15099254d918671Owen Lin            return false;
646666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
647666ea1b28a76aeba74744148b15099254d918671Owen Lin
648666ea1b28a76aeba74744148b15099254d918671Owen Lin        switch (event.getAction()) {
649666ea1b28a76aeba74744148b15099254d918671Owen Lin            case MotionEvent.ACTION_DOWN:
650666ea1b28a76aeba74744148b15099254d918671Owen Lin                if (cropImage.mWaitingToPick) {
651666ea1b28a76aeba74744148b15099254d918671Owen Lin                    recomputeFocus(event);
652666ea1b28a76aeba74744148b15099254d918671Owen Lin                } else {
653666ea1b28a76aeba74744148b15099254d918671Owen Lin                    for (int i = 0; i < mHighlightViews.size(); i++) {
654666ea1b28a76aeba74744148b15099254d918671Owen Lin                        HighlightView hv = mHighlightViews.get(i);
655666ea1b28a76aeba74744148b15099254d918671Owen Lin                        int edge = hv.getHit(event.getX(), event.getY());
656666ea1b28a76aeba74744148b15099254d918671Owen Lin                        if (edge != HighlightView.GROW_NONE) {
657666ea1b28a76aeba74744148b15099254d918671Owen Lin                            mMotionEdge = edge;
658666ea1b28a76aeba74744148b15099254d918671Owen Lin                            mMotionHighlightView = hv;
659666ea1b28a76aeba74744148b15099254d918671Owen Lin                            mLastX = event.getX();
660666ea1b28a76aeba74744148b15099254d918671Owen Lin                            mLastY = event.getY();
661666ea1b28a76aeba74744148b15099254d918671Owen Lin                            mMotionHighlightView.setMode(
662666ea1b28a76aeba74744148b15099254d918671Owen Lin                                    (edge == HighlightView.MOVE)
663666ea1b28a76aeba74744148b15099254d918671Owen Lin                                    ? HighlightView.ModifyMode.Move
664666ea1b28a76aeba74744148b15099254d918671Owen Lin                                    : HighlightView.ModifyMode.Grow);
665666ea1b28a76aeba74744148b15099254d918671Owen Lin                            break;
666666ea1b28a76aeba74744148b15099254d918671Owen Lin                        }
667666ea1b28a76aeba74744148b15099254d918671Owen Lin                    }
668666ea1b28a76aeba74744148b15099254d918671Owen Lin                }
669666ea1b28a76aeba74744148b15099254d918671Owen Lin                break;
670666ea1b28a76aeba74744148b15099254d918671Owen Lin            case MotionEvent.ACTION_UP:
671666ea1b28a76aeba74744148b15099254d918671Owen Lin                if (cropImage.mWaitingToPick) {
672666ea1b28a76aeba74744148b15099254d918671Owen Lin                    for (int i = 0; i < mHighlightViews.size(); i++) {
673666ea1b28a76aeba74744148b15099254d918671Owen Lin                        HighlightView hv = mHighlightViews.get(i);
674666ea1b28a76aeba74744148b15099254d918671Owen Lin                        if (hv.hasFocus()) {
675666ea1b28a76aeba74744148b15099254d918671Owen Lin                            cropImage.mCrop = hv;
676666ea1b28a76aeba74744148b15099254d918671Owen Lin                            for (int j = 0; j < mHighlightViews.size(); j++) {
677666ea1b28a76aeba74744148b15099254d918671Owen Lin                                if (j == i) {
678666ea1b28a76aeba74744148b15099254d918671Owen Lin                                    continue;
679666ea1b28a76aeba74744148b15099254d918671Owen Lin                                }
680666ea1b28a76aeba74744148b15099254d918671Owen Lin                                mHighlightViews.get(j).setHidden(true);
681666ea1b28a76aeba74744148b15099254d918671Owen Lin                            }
682666ea1b28a76aeba74744148b15099254d918671Owen Lin                            centerBasedOnHighlightView(hv);
683666ea1b28a76aeba74744148b15099254d918671Owen Lin                            ((CropImage) mContext).mWaitingToPick = false;
684666ea1b28a76aeba74744148b15099254d918671Owen Lin                            return true;
685666ea1b28a76aeba74744148b15099254d918671Owen Lin                        }
686666ea1b28a76aeba74744148b15099254d918671Owen Lin                    }
687666ea1b28a76aeba74744148b15099254d918671Owen Lin                } else if (mMotionHighlightView != null) {
688666ea1b28a76aeba74744148b15099254d918671Owen Lin                    centerBasedOnHighlightView(mMotionHighlightView);
689666ea1b28a76aeba74744148b15099254d918671Owen Lin                    mMotionHighlightView.setMode(
690666ea1b28a76aeba74744148b15099254d918671Owen Lin                            HighlightView.ModifyMode.None);
691666ea1b28a76aeba74744148b15099254d918671Owen Lin                }
692666ea1b28a76aeba74744148b15099254d918671Owen Lin                mMotionHighlightView = null;
693666ea1b28a76aeba74744148b15099254d918671Owen Lin                break;
694666ea1b28a76aeba74744148b15099254d918671Owen Lin            case MotionEvent.ACTION_MOVE:
695666ea1b28a76aeba74744148b15099254d918671Owen Lin                if (cropImage.mWaitingToPick) {
696666ea1b28a76aeba74744148b15099254d918671Owen Lin                    recomputeFocus(event);
697666ea1b28a76aeba74744148b15099254d918671Owen Lin                } else if (mMotionHighlightView != null) {
698666ea1b28a76aeba74744148b15099254d918671Owen Lin                    mMotionHighlightView.handleMotion(mMotionEdge,
699666ea1b28a76aeba74744148b15099254d918671Owen Lin                            event.getX() - mLastX,
700666ea1b28a76aeba74744148b15099254d918671Owen Lin                            event.getY() - mLastY);
701666ea1b28a76aeba74744148b15099254d918671Owen Lin                    mLastX = event.getX();
702666ea1b28a76aeba74744148b15099254d918671Owen Lin                    mLastY = event.getY();
703666ea1b28a76aeba74744148b15099254d918671Owen Lin
704666ea1b28a76aeba74744148b15099254d918671Owen Lin                    if (true) {
705666ea1b28a76aeba74744148b15099254d918671Owen Lin                        // This section of code is optional. It has some user
706666ea1b28a76aeba74744148b15099254d918671Owen Lin                        // benefit in that moving the crop rectangle against
707666ea1b28a76aeba74744148b15099254d918671Owen Lin                        // the edge of the screen causes scrolling but it means
708666ea1b28a76aeba74744148b15099254d918671Owen Lin                        // that the crop rectangle is no longer fixed under
709666ea1b28a76aeba74744148b15099254d918671Owen Lin                        // the user's finger.
710666ea1b28a76aeba74744148b15099254d918671Owen Lin                        ensureVisible(mMotionHighlightView);
711666ea1b28a76aeba74744148b15099254d918671Owen Lin                    }
712666ea1b28a76aeba74744148b15099254d918671Owen Lin                }
713666ea1b28a76aeba74744148b15099254d918671Owen Lin                break;
714666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
715666ea1b28a76aeba74744148b15099254d918671Owen Lin
716666ea1b28a76aeba74744148b15099254d918671Owen Lin        switch (event.getAction()) {
717666ea1b28a76aeba74744148b15099254d918671Owen Lin            case MotionEvent.ACTION_UP:
718666ea1b28a76aeba74744148b15099254d918671Owen Lin                center(true, true);
719666ea1b28a76aeba74744148b15099254d918671Owen Lin                break;
720666ea1b28a76aeba74744148b15099254d918671Owen Lin            case MotionEvent.ACTION_MOVE:
721666ea1b28a76aeba74744148b15099254d918671Owen Lin                // if we're not zoomed then there's no point in even allowing
722666ea1b28a76aeba74744148b15099254d918671Owen Lin                // the user to move the image around.  This call to center puts
723666ea1b28a76aeba74744148b15099254d918671Owen Lin                // it back to the normalized location (with false meaning don't
724666ea1b28a76aeba74744148b15099254d918671Owen Lin                // animate).
725666ea1b28a76aeba74744148b15099254d918671Owen Lin                if (getScale() == 1F) {
726666ea1b28a76aeba74744148b15099254d918671Owen Lin                    center(true, true);
727666ea1b28a76aeba74744148b15099254d918671Owen Lin                }
728666ea1b28a76aeba74744148b15099254d918671Owen Lin                break;
729666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
730666ea1b28a76aeba74744148b15099254d918671Owen Lin
731666ea1b28a76aeba74744148b15099254d918671Owen Lin        return true;
732666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
733666ea1b28a76aeba74744148b15099254d918671Owen Lin
734666ea1b28a76aeba74744148b15099254d918671Owen Lin    // Pan the displayed image to make sure the cropping rectangle is visible.
735666ea1b28a76aeba74744148b15099254d918671Owen Lin    private void ensureVisible(HighlightView hv) {
736666ea1b28a76aeba74744148b15099254d918671Owen Lin        Rect r = hv.mDrawRect;
737666ea1b28a76aeba74744148b15099254d918671Owen Lin
738666ea1b28a76aeba74744148b15099254d918671Owen Lin        int panDeltaX1 = Math.max(0, mLeft - r.left);
739666ea1b28a76aeba74744148b15099254d918671Owen Lin        int panDeltaX2 = Math.min(0, mRight - r.right);
740666ea1b28a76aeba74744148b15099254d918671Owen Lin
741666ea1b28a76aeba74744148b15099254d918671Owen Lin        int panDeltaY1 = Math.max(0, mTop - r.top);
742666ea1b28a76aeba74744148b15099254d918671Owen Lin        int panDeltaY2 = Math.min(0, mBottom - r.bottom);
743666ea1b28a76aeba74744148b15099254d918671Owen Lin
744666ea1b28a76aeba74744148b15099254d918671Owen Lin        int panDeltaX = panDeltaX1 != 0 ? panDeltaX1 : panDeltaX2;
745666ea1b28a76aeba74744148b15099254d918671Owen Lin        int panDeltaY = panDeltaY1 != 0 ? panDeltaY1 : panDeltaY2;
746666ea1b28a76aeba74744148b15099254d918671Owen Lin
747666ea1b28a76aeba74744148b15099254d918671Owen Lin        if (panDeltaX != 0 || panDeltaY != 0) {
748666ea1b28a76aeba74744148b15099254d918671Owen Lin            panBy(panDeltaX, panDeltaY);
749666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
750666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
751666ea1b28a76aeba74744148b15099254d918671Owen Lin
752666ea1b28a76aeba74744148b15099254d918671Owen Lin    // If the cropping rectangle's size changed significantly, change the
753666ea1b28a76aeba74744148b15099254d918671Owen Lin    // view's center and scale according to the cropping rectangle.
754666ea1b28a76aeba74744148b15099254d918671Owen Lin    private void centerBasedOnHighlightView(HighlightView hv) {
755666ea1b28a76aeba74744148b15099254d918671Owen Lin        Rect drawRect = hv.mDrawRect;
756666ea1b28a76aeba74744148b15099254d918671Owen Lin
757666ea1b28a76aeba74744148b15099254d918671Owen Lin        float width = drawRect.width();
758666ea1b28a76aeba74744148b15099254d918671Owen Lin        float height = drawRect.height();
759666ea1b28a76aeba74744148b15099254d918671Owen Lin
760666ea1b28a76aeba74744148b15099254d918671Owen Lin        float thisWidth = getWidth();
761666ea1b28a76aeba74744148b15099254d918671Owen Lin        float thisHeight = getHeight();
762666ea1b28a76aeba74744148b15099254d918671Owen Lin
763666ea1b28a76aeba74744148b15099254d918671Owen Lin        float z1 = thisWidth / width * .6F;
764666ea1b28a76aeba74744148b15099254d918671Owen Lin        float z2 = thisHeight / height * .6F;
765666ea1b28a76aeba74744148b15099254d918671Owen Lin
766666ea1b28a76aeba74744148b15099254d918671Owen Lin        float zoom = Math.min(z1, z2);
767666ea1b28a76aeba74744148b15099254d918671Owen Lin        zoom = zoom * this.getScale();
768666ea1b28a76aeba74744148b15099254d918671Owen Lin        zoom = Math.max(1F, zoom);
769666ea1b28a76aeba74744148b15099254d918671Owen Lin
770666ea1b28a76aeba74744148b15099254d918671Owen Lin        if ((Math.abs(zoom - getScale()) / zoom) > .1) {
771666ea1b28a76aeba74744148b15099254d918671Owen Lin            float [] coordinates = new float[] {hv.mCropRect.centerX(),
772666ea1b28a76aeba74744148b15099254d918671Owen Lin                                                hv.mCropRect.centerY()};
773666ea1b28a76aeba74744148b15099254d918671Owen Lin            getImageMatrix().mapPoints(coordinates);
774666ea1b28a76aeba74744148b15099254d918671Owen Lin            zoomTo(zoom, coordinates[0], coordinates[1], 300F);
775666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
776666ea1b28a76aeba74744148b15099254d918671Owen Lin
777666ea1b28a76aeba74744148b15099254d918671Owen Lin        ensureVisible(hv);
778666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
779666ea1b28a76aeba74744148b15099254d918671Owen Lin
780666ea1b28a76aeba74744148b15099254d918671Owen Lin    @Override
781666ea1b28a76aeba74744148b15099254d918671Owen Lin    protected void onDraw(Canvas canvas) {
782666ea1b28a76aeba74744148b15099254d918671Owen Lin        super.onDraw(canvas);
783666ea1b28a76aeba74744148b15099254d918671Owen Lin        for (int i = 0; i < mHighlightViews.size(); i++) {
784666ea1b28a76aeba74744148b15099254d918671Owen Lin            mHighlightViews.get(i).draw(canvas);
785666ea1b28a76aeba74744148b15099254d918671Owen Lin        }
786666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
787666ea1b28a76aeba74744148b15099254d918671Owen Lin
788666ea1b28a76aeba74744148b15099254d918671Owen Lin    public void add(HighlightView hv) {
789666ea1b28a76aeba74744148b15099254d918671Owen Lin        mHighlightViews.add(hv);
790666ea1b28a76aeba74744148b15099254d918671Owen Lin        invalidate();
791666ea1b28a76aeba74744148b15099254d918671Owen Lin    }
792666ea1b28a76aeba74744148b15099254d918671Owen Lin}
793