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