PhotoUI.java revision 02b9b9af097ac7886ec1d23392cd87c9fbcb186f
1d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb/*
26432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu * Copyright (C) 2012 The Android Open Source Project
3d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb *
4d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb * Licensed under the Apache License, Version 2.0 (the "License");
5d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb * you may not use this file except in compliance with the License.
6d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb * You may obtain a copy of the License at
7d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb *
8d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb *      http://www.apache.org/licenses/LICENSE-2.0
9d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb *
10d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb * Unless required by applicable law or agreed to in writing, software
11d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb * distributed under the License is distributed on an "AS IS" BASIS,
12d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb * See the License for the specific language governing permissions and
14d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb * limitations under the License.
15d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb */
16d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
17d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbpackage com.android.camera;
18d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
19db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liuimport android.app.Dialog;
20db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liuimport android.content.DialogInterface;
2137f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberlingimport android.graphics.Bitmap;
22b4a2222950f627a39267636fba19649974cb8734Spike Spragueimport android.graphics.Color;
236432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liuimport android.graphics.Matrix;
246c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liuimport android.graphics.RectF;
256432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liuimport android.graphics.SurfaceTexture;
26d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport android.hardware.Camera;
27d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport android.hardware.Camera.Face;
2837f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberlingimport android.os.AsyncTask;
291d943647c5b632588c4858ded04770e846341f1bSascha Haeberlingimport android.os.Build;
30f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liuimport android.view.GestureDetector;
31f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liuimport android.view.MotionEvent;
32d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport android.view.View;
33d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport android.view.ViewGroup;
34b4a2222950f627a39267636fba19649974cb8734Spike Spragueimport android.widget.FrameLayout;
35b4a2222950f627a39267636fba19649974cb8734Spike Spragueimport android.widget.ImageView;
36d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
37d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport com.android.camera.FocusOverlayManager.FocusUI;
381045fefdf22bd58fa911b100e7db5750f7efa3e6Angus Kongimport com.android.camera.cameradevice.CameraManager;
395596b4c902dcb685928b43678f428746ca5ffd08Angus Kongimport com.android.camera.debug.Log;
406c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liuimport com.android.camera.ui.CountDownView;
41d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport com.android.camera.ui.FaceView;
42f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liuimport com.android.camera.ui.PreviewOverlay;
4306db742814dd635d100639f977fcfdc904deb778Doris Liuimport com.android.camera.ui.PreviewStatusListener;
44b50b5cbfbc0a67db6fc43373363b10381c9c61a3Angus Kongimport com.android.camera.util.CameraUtil;
45db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liuimport com.android.camera.widget.AspectRatioDialogLayout;
46db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liuimport com.android.camera.widget.AspectRatioSelector;
47db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liuimport com.android.camera.widget.LocationDialogLayout;
488e963a5a6016d246184ed65906f9d103e92b17e2Sascha Haeberlingimport com.android.camera2.R;
49b50b5cbfbc0a67db6fc43373363b10381c9c61a3Angus Kong
50b50b5cbfbc0a67db6fc43373363b10381c9c61a3Angus Kongimport java.util.List;
51d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
52482de029dc20e0a577388a602985fb31c3200309Doris Liupublic class PhotoUI implements PreviewStatusListener,
536c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    CameraManager.CameraFaceDetectionCallback, PreviewStatusListener.PreviewAreaChangedListener {
54d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
555596b4c902dcb685928b43678f428746ca5ffd08Angus Kong    private static final Log.Tag TAG = new Log.Tag("PhotoUI");
5637f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling    private static final int DOWN_SAMPLE_FACTOR = 4;
5770da918464276b110c43868caa272c97baadb89eDoris Liu    private static final float UNSET = 0f;
580f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague
59f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu    private final PreviewOverlay mPreviewOverlay;
60482de029dc20e0a577388a602985fb31c3200309Doris Liu    private final FocusUI mFocusUI;
61e2914fddcd6d4f78d812ef818d43364d9aa469d4Sascha Haeberling    private final CameraActivity mActivity;
62e2914fddcd6d4f78d812ef818d43364d9aa469d4Sascha Haeberling    private final PhotoController mController;
63d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
64e2914fddcd6d4f78d812ef818d43364d9aa469d4Sascha Haeberling    private final View mRootView;
65db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    private Dialog mDialog = null;
66d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
67d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu    // TODO: Remove face view logic if UX does not bring it back within a month.
681d943647c5b632588c4858ded04770e846341f1bSascha Haeberling    private final FaceView mFaceView = null;
6936e56fba281292255a01ee00b4bee067fa09ab59Doris Liu    private DecodeImageForReview mDecodeTaskForReview = null;
70d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
71d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    private int mZoomMax;
72d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    private List<Integer> mZoomRatios;
73d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
74d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    private int mPreviewWidth = 0;
75d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    private int mPreviewHeight = 0;
7670da918464276b110c43868caa272c97baadb89eDoris Liu    private float mAspectRatio = UNSET;
770744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
78b4a2222950f627a39267636fba19649974cb8734Spike Sprague    private ImageView mIntentReviewImageView;
79b4a2222950f627a39267636fba19649974cb8734Spike Sprague
8006db742814dd635d100639f977fcfdc904deb778Doris Liu    private final GestureDetector.OnGestureListener mPreviewGestureListener
8106db742814dd635d100639f977fcfdc904deb778Doris Liu            = new GestureDetector.SimpleOnGestureListener() {
8206db742814dd635d100639f977fcfdc904deb778Doris Liu        @Override
8306db742814dd635d100639f977fcfdc904deb778Doris Liu        public boolean onSingleTapUp(MotionEvent ev) {
8406db742814dd635d100639f977fcfdc904deb778Doris Liu            mController.onSingleTapUp(null, (int) ev.getX(), (int) ev.getY());
8506db742814dd635d100639f977fcfdc904deb778Doris Liu            return true;
8606db742814dd635d100639f977fcfdc904deb778Doris Liu        }
8706db742814dd635d100639f977fcfdc904deb778Doris Liu    };
88db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    private final DialogInterface.OnDismissListener mOnDismissListener
89db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            = new DialogInterface.OnDismissListener() {
90db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        @Override
91db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        public void onDismiss(DialogInterface dialog) {
92db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            mDialog = null;
93db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        }
94db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    };
9508b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu    private Runnable mRunnableForNextFrame = null;
966c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    private CountDownView mCountdownView;
970744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
9806db742814dd635d100639f977fcfdc904deb778Doris Liu    @Override
9906db742814dd635d100639f977fcfdc904deb778Doris Liu    public GestureDetector.OnGestureListener getGestureListener() {
10006db742814dd635d100639f977fcfdc904deb778Doris Liu        return mPreviewGestureListener;
10106db742814dd635d100639f977fcfdc904deb778Doris Liu    }
10206db742814dd635d100639f977fcfdc904deb778Doris Liu
1034a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu    @Override
104d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    public View.OnTouchListener getTouchListener() {
105d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        return null;
106d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    }
107d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren
108d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    @Override
1094a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu    public void onPreviewLayoutChanged(View v, int left, int top, int right,
1104a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu            int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
1114a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu        int width = right - left;
1124a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu        int height = bottom - top;
1134a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu        if (mPreviewWidth != width || mPreviewHeight != height) {
1144a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu            mPreviewWidth = width;
1154a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu            mPreviewHeight = height;
116d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
1174a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu    }
118d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
11970da918464276b110c43868caa272c97baadb89eDoris Liu    @Override
12070da918464276b110c43868caa272c97baadb89eDoris Liu    public boolean shouldAutoAdjustTransformMatrixOnLayout() {
12170da918464276b110c43868caa272c97baadb89eDoris Liu        return true;
12270da918464276b110c43868caa272c97baadb89eDoris Liu    }
12370da918464276b110c43868caa272c97baadb89eDoris Liu
12470da918464276b110c43868caa272c97baadb89eDoris Liu    @Override
12570da918464276b110c43868caa272c97baadb89eDoris Liu    public boolean shouldAutoAdjustBottomBar() {
12670da918464276b110c43868caa272c97baadb89eDoris Liu        return true;
12770da918464276b110c43868caa272c97baadb89eDoris Liu    }
12870da918464276b110c43868caa272c97baadb89eDoris Liu
12911ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu    @Override
13011ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu    public void onPreviewFlipped() {
13111ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu        mController.updateCameraOrientation();
13211ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu    }
13311ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu
13408b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu    /**
13508b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu     * Sets the runnable to run when the next frame comes in.
13608b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu     */
13708b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu    public void setRunnableForNextFrame(Runnable runnable) {
13808b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu        mRunnableForNextFrame = runnable;
13908b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu    }
14008b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu
1416c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    /**
1426c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu     * Starts the countdown timer.
1436c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu     *
1446c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu     * @param sec seconds to countdown
1456c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu     */
1466c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    public void startCountdown(int sec) {
1476c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu        mCountdownView.startCountDown(sec);
1486c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    }
1496c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu
1506c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    /**
1516c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu     * Sets a listener that gets notified when the countdown is finished.
1526c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu     */
1536c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    public void setCountdownFinishedListener(CountDownView.OnCountDownStatusListener listener) {
1546c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu        mCountdownView.setCountDownStatusListener(listener);
1556c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    }
1566c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu
1576c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    /**
1586c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu     * Returns whether the countdown is on-going.
1596c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu     */
1606c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    public boolean isCountingDown() {
1616c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu        return mCountdownView.isCountingDown();
1626c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    }
1636c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu
1646c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    /**
1656c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu     * Cancels the on-going countdown, if any.
1666c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu     */
1676c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    public void cancelCountDown() {
1686c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu        mCountdownView.cancelCountDown();
1696c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    }
1706c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu
1716c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    @Override
1726c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    public void onPreviewAreaChanged(RectF previewArea) {
1736c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu        if (mFaceView != null) {
1746c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu            mFaceView.onPreviewAreaChanged(previewArea);
1756c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu        }
1766c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu        mCountdownView.onPreviewAreaChanged(previewArea);
1776c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    }
1786c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu
17936e56fba281292255a01ee00b4bee067fa09ab59Doris Liu    private class DecodeTask extends AsyncTask<Void, Void, Bitmap> {
18037f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling        private final byte [] mData;
181e2914fddcd6d4f78d812ef818d43364d9aa469d4Sascha Haeberling        private final int mOrientation;
182e2914fddcd6d4f78d812ef818d43364d9aa469d4Sascha Haeberling        private final boolean mMirror;
183c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu
18429da2db13029f8896018836693139a05d1139362Doris Liu        public DecodeTask(byte[] data, int orientation, boolean mirror) {
18537f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling            mData = data;
186ce2acbcb77225b6d429a23e00f69aadde8c2378bDoris Liu            mOrientation = orientation;
18729da2db13029f8896018836693139a05d1139362Doris Liu            mMirror = mirror;
188c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu        }
189c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu
190c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu        @Override
19136e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        protected Bitmap doInBackground(Void... params) {
19237f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling            // Decode image in background.
193ce2acbcb77225b6d429a23e00f69aadde8c2378bDoris Liu            Bitmap bitmap = CameraUtil.downSample(mData, DOWN_SAMPLE_FACTOR);
19429da2db13029f8896018836693139a05d1139362Doris Liu            if (mOrientation != 0 || mMirror) {
195ce2acbcb77225b6d429a23e00f69aadde8c2378bDoris Liu                Matrix m = new Matrix();
19629da2db13029f8896018836693139a05d1139362Doris Liu                if (mMirror) {
19729da2db13029f8896018836693139a05d1139362Doris Liu                    // Flip horizontally
19829da2db13029f8896018836693139a05d1139362Doris Liu                    m.setScale(-1f, 1f);
19929da2db13029f8896018836693139a05d1139362Doris Liu                }
200cec75e408a2d451b90bac5f06e10906ffcafff33Andy Huibers                m.preRotate(mOrientation);
201ce2acbcb77225b6d429a23e00f69aadde8c2378bDoris Liu                return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m,
202ce2acbcb77225b6d429a23e00f69aadde8c2378bDoris Liu                        false);
203ce2acbcb77225b6d429a23e00f69aadde8c2378bDoris Liu            }
204ce2acbcb77225b6d429a23e00f69aadde8c2378bDoris Liu            return bitmap;
20537f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling        }
20637f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling    }
207c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu
20836e56fba281292255a01ee00b4bee067fa09ab59Doris Liu    private class DecodeImageForReview extends DecodeTask {
20936e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        public DecodeImageForReview(byte[] data, int orientation, boolean mirror) {
21036e56fba281292255a01ee00b4bee067fa09ab59Doris Liu            super(data, orientation, mirror);
21136e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        }
21236e56fba281292255a01ee00b4bee067fa09ab59Doris Liu
21336e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        @Override
21436e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        protected void onPostExecute(Bitmap bitmap) {
21536e56fba281292255a01ee00b4bee067fa09ab59Doris Liu            if (isCancelled()) {
21636e56fba281292255a01ee00b4bee067fa09ab59Doris Liu                return;
21736e56fba281292255a01ee00b4bee067fa09ab59Doris Liu            }
218b4a2222950f627a39267636fba19649974cb8734Spike Sprague
219b4a2222950f627a39267636fba19649974cb8734Spike Sprague            mIntentReviewImageView.setImageBitmap(bitmap);
220b4a2222950f627a39267636fba19649974cb8734Spike Sprague            showIntentReviewImageView();
221b4a2222950f627a39267636fba19649974cb8734Spike Sprague
22236e56fba281292255a01ee00b4bee067fa09ab59Doris Liu            mDecodeTaskForReview = null;
22336e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        }
22436e56fba281292255a01ee00b4bee067fa09ab59Doris Liu    }
22536e56fba281292255a01ee00b4bee067fa09ab59Doris Liu
226d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public PhotoUI(CameraActivity activity, PhotoController controller, View parent) {
227d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        mActivity = activity;
228d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        mController = controller;
229d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        mRootView = parent;
230d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
231f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        ViewGroup moduleRoot = (ViewGroup) mRootView.findViewById(R.id.module_layout);
232d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        mActivity.getLayoutInflater().inflate(R.layout.photo_module,
233e2914fddcd6d4f78d812ef818d43364d9aa469d4Sascha Haeberling                 moduleRoot, true);
234d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        initIndicators();
235482de029dc20e0a577388a602985fb31c3200309Doris Liu        mFocusUI = (FocusUI) mRootView.findViewById(R.id.focus_overlay);
236f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu        mPreviewOverlay = (PreviewOverlay) mRootView.findViewById(R.id.preview_overlay);
2376c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu        mCountdownView = (CountDownView) mRootView.findViewById(R.id.count_down_view);
238b4a2222950f627a39267636fba19649974cb8734Spike Sprague
239b4a2222950f627a39267636fba19649974cb8734Spike Sprague        if (mController.isImageCaptureIntent()) {
24002b9b9af097ac7886ec1d23392cd87c9fbcb186fSpike Sprague            initIntentReviewImageView();
241b4a2222950f627a39267636fba19649974cb8734Spike Sprague        }
242b4a2222950f627a39267636fba19649974cb8734Spike Sprague    }
243b4a2222950f627a39267636fba19649974cb8734Spike Sprague
24402b9b9af097ac7886ec1d23392cd87c9fbcb186fSpike Sprague    private void initIntentReviewImageView() {
24502b9b9af097ac7886ec1d23392cd87c9fbcb186fSpike Sprague        mIntentReviewImageView = (ImageView) mRootView.findViewById(R.id.intent_review_imageview);
246b4a2222950f627a39267636fba19649974cb8734Spike Sprague        mActivity.getCameraAppUI().addPreviewAreaChangedListener(
247b4a2222950f627a39267636fba19649974cb8734Spike Sprague                new PreviewStatusListener.PreviewAreaChangedListener() {
248b4a2222950f627a39267636fba19649974cb8734Spike Sprague                    @Override
249b4a2222950f627a39267636fba19649974cb8734Spike Sprague                    public void onPreviewAreaChanged(RectF previewArea) {
250b4a2222950f627a39267636fba19649974cb8734Spike Sprague                        FrameLayout.LayoutParams params =
251b4a2222950f627a39267636fba19649974cb8734Spike Sprague                            (FrameLayout.LayoutParams) mIntentReviewImageView.getLayoutParams();
252b4a2222950f627a39267636fba19649974cb8734Spike Sprague                        params.width = (int) previewArea.width();
253b4a2222950f627a39267636fba19649974cb8734Spike Sprague                        params.height = (int) previewArea.height();
254b4a2222950f627a39267636fba19649974cb8734Spike Sprague                        params.setMargins((int) previewArea.left, (int) previewArea.top, 0, 0);
255b4a2222950f627a39267636fba19649974cb8734Spike Sprague                        mIntentReviewImageView.setLayoutParams(params);
256b4a2222950f627a39267636fba19649974cb8734Spike Sprague                    }
257b4a2222950f627a39267636fba19649974cb8734Spike Sprague                });
258b4a2222950f627a39267636fba19649974cb8734Spike Sprague    }
259b4a2222950f627a39267636fba19649974cb8734Spike Sprague
260b4a2222950f627a39267636fba19649974cb8734Spike Sprague    /**
261b4a2222950f627a39267636fba19649974cb8734Spike Sprague     * Show the image review over the live preview for intent captures.
262b4a2222950f627a39267636fba19649974cb8734Spike Sprague     */
263b4a2222950f627a39267636fba19649974cb8734Spike Sprague    public void showIntentReviewImageView() {
264b4a2222950f627a39267636fba19649974cb8734Spike Sprague        if (mIntentReviewImageView != null) {
265b4a2222950f627a39267636fba19649974cb8734Spike Sprague            mIntentReviewImageView.setVisibility(View.VISIBLE);
266b4a2222950f627a39267636fba19649974cb8734Spike Sprague        }
2676432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    }
2686432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu
269b4a2222950f627a39267636fba19649974cb8734Spike Sprague    /**
270b4a2222950f627a39267636fba19649974cb8734Spike Sprague     * Hide the image review over the live preview for intent captures.
271b4a2222950f627a39267636fba19649974cb8734Spike Sprague     */
272b4a2222950f627a39267636fba19649974cb8734Spike Sprague    public void hideIntentReviewImageView() {
273b4a2222950f627a39267636fba19649974cb8734Spike Sprague        if (mIntentReviewImageView != null) {
274b4a2222950f627a39267636fba19649974cb8734Spike Sprague            mIntentReviewImageView.setVisibility(View.INVISIBLE);
275b4a2222950f627a39267636fba19649974cb8734Spike Sprague        }
276b4a2222950f627a39267636fba19649974cb8734Spike Sprague    }
277b4a2222950f627a39267636fba19649974cb8734Spike Sprague
278b4a2222950f627a39267636fba19649974cb8734Spike Sprague
279482de029dc20e0a577388a602985fb31c3200309Doris Liu    public FocusUI getFocusUI() {
280482de029dc20e0a577388a602985fb31c3200309Doris Liu        return mFocusUI;
281482de029dc20e0a577388a602985fb31c3200309Doris Liu    }
282482de029dc20e0a577388a602985fb31c3200309Doris Liu
283d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu    public void updatePreviewAspectRatio(float aspectRatio) {
284d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu        if (aspectRatio <= 0) {
285d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu            Log.e(TAG, "Invalid aspect ratio: " + aspectRatio);
286d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu            return;
287d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu        }
288d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu        if (aspectRatio < 1f) {
289d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu            aspectRatio = 1f / aspectRatio;
290d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu        }
291d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu
292d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu        if (mAspectRatio != aspectRatio) {
293d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu            mAspectRatio = aspectRatio;
294d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu            // Update transform matrix with the new aspect ratio.
29570da918464276b110c43868caa272c97baadb89eDoris Liu            mController.updatePreviewAspectRatio(mAspectRatio);
296d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu        }
297d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu    }
298d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu
299dcccc510652b835fdbd39310a07849af8203052aAngus Kong    @Override
3006432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
301d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        mController.onPreviewUIReady();
3026432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    }
303d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
304dcccc510652b835fdbd39310a07849af8203052aAngus Kong    @Override
3056432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
3066432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu        // Ignored, Camera does all the work for us
3076432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    }
3086432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu
309dcccc510652b835fdbd39310a07849af8203052aAngus Kong    @Override
3106432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
311d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        mController.onPreviewUIDestroyed();
312d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        return true;
3136432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    }
3146432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu
3157b265a6b2f55c6ae7afc30e63ba324c4084a5d8eztenghui    @Override
3166432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
31708b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu        if (mRunnableForNextFrame != null) {
31808b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu            mRootView.post(mRunnableForNextFrame);
31908b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu            mRunnableForNextFrame = null;
32008b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu        }
321d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
322d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
323d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public View getRootView() {
324d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        return mRootView;
325d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
326d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
327d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    private void initIndicators() {
3280744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        // TODO init toggle buttons on bottom bar here
329d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
330d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
331b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren    public void onCameraOpened(Camera.Parameters params) {
332eb3134f6ecc42f7d98625ca2c0ddfb06c9f07c43Spike Sprague        initializeZoom(params);
333eb3134f6ecc42f7d98625ca2c0ddfb06c9f07c43Spike Sprague    }
334eb3134f6ecc42f7d98625ca2c0ddfb06c9f07c43Spike Sprague
3350a6a8d8e4e1c9796aac606379a42970cdffb8911Erin Dahlgren    public void animateCapture(final byte[] jpegData, int orientation, boolean mirror) {
3360a6a8d8e4e1c9796aac606379a42970cdffb8911Erin Dahlgren        // Decode jpeg byte array and then animate the jpeg
3370a6a8d8e4e1c9796aac606379a42970cdffb8911Erin Dahlgren        DecodeTask task = new DecodeTask(jpegData, orientation, mirror);
3380a6a8d8e4e1c9796aac606379a42970cdffb8911Erin Dahlgren        task.execute();
339eb3134f6ecc42f7d98625ca2c0ddfb06c9f07c43Spike Sprague    }
340d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
341d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    // called from onResume but only the first time
342ffbc43c3dd3c94a968a41431fb07645a13696c4aKevin Gabayan    public void initializeFirstTime() {
3430744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
344d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
345d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
346d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    // called from onResume every other time
347d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void initializeSecondTime(Camera.Parameters params) {
348d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        initializeZoom(params);
349d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        if (mController.isImageCaptureIntent()) {
350d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            hidePostCaptureAlert();
351d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
352357b7673f03d9b45d281d585cc3f4f87dc7d727bErin Dahlgren        // Removes pie menu.
353d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
354d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
355db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    public void showLocationAndAspectRatioDialog(
356db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            final PhotoModule.LocationDialogCallback locationCallback,
357db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            final PhotoModule.AspectRatioDialogCallback aspectRatioDialogCallback) {
358db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        setDialog(new Dialog(mActivity,
359db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                android.R.style.Theme_Black_NoTitleBar_Fullscreen));
360db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        final LocationDialogLayout locationDialogLayout = (LocationDialogLayout) mActivity
361db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                .getLayoutInflater().inflate(R.layout.location_dialog_layout, null);
362db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        locationDialogLayout.setLocationTaggingSelectionListener(
363db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                new LocationDialogLayout.LocationTaggingSelectionListener() {
364db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            @Override
365db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            public void onLocationTaggingSelected(boolean selected) {
366db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                // Update setting.
367db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                locationCallback.onLocationTaggingSelected(selected);
3681d943647c5b632588c4858ded04770e846341f1bSascha Haeberling
3691d943647c5b632588c4858ded04770e846341f1bSascha Haeberling                if (showAspectRatioDialogOnThisDevice()) {
3701d943647c5b632588c4858ded04770e846341f1bSascha Haeberling                    // Go to next page.
3711d943647c5b632588c4858ded04770e846341f1bSascha Haeberling                    showAspectRatioDialog(aspectRatioDialogCallback, mDialog);
3721d943647c5b632588c4858ded04770e846341f1bSascha Haeberling                } else {
3731d943647c5b632588c4858ded04770e846341f1bSascha Haeberling                    // If we don't want to show the aspect ratio dialog,
3741d943647c5b632588c4858ded04770e846341f1bSascha Haeberling                    // dismiss the dialog right after the user chose the
3751d943647c5b632588c4858ded04770e846341f1bSascha Haeberling                    // location setting.
3761d943647c5b632588c4858ded04770e846341f1bSascha Haeberling                    if (mDialog != null) {
3771d943647c5b632588c4858ded04770e846341f1bSascha Haeberling                        mDialog.dismiss();
3781d943647c5b632588c4858ded04770e846341f1bSascha Haeberling                    }
3791d943647c5b632588c4858ded04770e846341f1bSascha Haeberling                }
380db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            }
381db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        });
382db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        mDialog.setContentView(locationDialogLayout, new ViewGroup.LayoutParams(
383db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
384db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        mDialog.show();
385db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    }
386db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu
387db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    /**
388db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu     * Dismisses previous dialog if any, sets current dialog to the given dialog,
389db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu     * and set the on dismiss listener for the given dialog.
390db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu     * @param dialog dialog to show
391db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu     */
392db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    private void setDialog(Dialog dialog) {
393db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        if (mDialog != null) {
394db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            mDialog.setOnDismissListener(null);
395db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            mDialog.dismiss();
396db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        }
397db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        mDialog = dialog;
398db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        if (mDialog != null) {
399db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            mDialog.setOnDismissListener(mOnDismissListener);
400db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        }
401db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    }
402db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu
403db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    public void showAspectRatioDialog(final PhotoModule.AspectRatioDialogCallback callback) {
4041d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        if (showAspectRatioDialogOnThisDevice()) {
4051d943647c5b632588c4858ded04770e846341f1bSascha Haeberling            setDialog(new Dialog(mActivity, android.R.style.Theme_Black_NoTitleBar_Fullscreen));
4061d943647c5b632588c4858ded04770e846341f1bSascha Haeberling            showAspectRatioDialog(callback, mDialog);
4071d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        }
408db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    }
409db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu
410db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    private void showAspectRatioDialog(final PhotoModule.AspectRatioDialogCallback callback,
411db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            final Dialog aspectRatioDialog) {
412db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        if (aspectRatioDialog == null) {
413db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            Log.e(TAG, "Dialog for aspect ratio is null.");
414db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            return;
415db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        }
416db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        final AspectRatioDialogLayout aspectRatioDialogLayout =
417db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                (AspectRatioDialogLayout) mActivity
418db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                .getLayoutInflater().inflate(R.layout.aspect_ratio_dialog_layout, null);
419db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        aspectRatioDialogLayout.initialize(
420db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                new AspectRatioDialogLayout.AspectRatioChangedListener() {
421db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                    @Override
422db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                    public void onAspectRatioChanged(AspectRatioSelector.AspectRatio aspectRatio) {
423db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                        // callback to set picture size.
42408b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu                        callback.onAspectRatioSelected(aspectRatio, new Runnable() {
42508b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu                            @Override
42608b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu                            public void run() {
42708b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu                                if (mDialog != null) {
42808b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu                                    mDialog.dismiss();
42908b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu                                }
43008b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu                            }
43108b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu                        });
432db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                    }
433e811b29f6707a6ea8f066e6f5b9cb0fc99d2dcd6Sascha Haeberling                }, callback.getCurrentAspectRatio());
434db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        aspectRatioDialog.setContentView(aspectRatioDialogLayout, new ViewGroup.LayoutParams(
435db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
436db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        aspectRatioDialog.show();
4376a83d528b09c55ade6ad44b82c81d4476ac57441Doris Liu    }
4386a83d528b09c55ade6ad44b82c81d4476ac57441Doris Liu
4391d943647c5b632588c4858ded04770e846341f1bSascha Haeberling    /**
4401d943647c5b632588c4858ded04770e846341f1bSascha Haeberling     * @return Whether this is a device that we should show the aspect ratio
4411d943647c5b632588c4858ded04770e846341f1bSascha Haeberling     *         intro dialog on.
4421d943647c5b632588c4858ded04770e846341f1bSascha Haeberling     */
4431d943647c5b632588c4858ded04770e846341f1bSascha Haeberling    private boolean showAspectRatioDialogOnThisDevice() {
4441d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        // We only want to show that dialog on N4 and N5
4451d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        return "hammerhead".equals(Build.DEVICE) || "mako".equals(Build.DEVICE);
4461d943647c5b632588c4858ded04770e846341f1bSascha Haeberling    }
4471d943647c5b632588c4858ded04770e846341f1bSascha Haeberling
448d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void initializeZoom(Camera.Parameters params) {
4491d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        if ((params == null) || !params.isZoomSupported()) {
4501d943647c5b632588c4858ded04770e846341f1bSascha Haeberling            return;
4511d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        }
452d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        mZoomMax = params.getMaxZoom();
453d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        mZoomRatios = params.getZoomRatios();
454d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        // Currently we use immediate zoom for fast zooming to get better UX and
455d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        // there is no plan to take advantage of the smooth zoom.
456f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu        // TODO: Need to setup a path to AppUI to do this
457f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu        mPreviewOverlay.setupZoom(mZoomMax, params.getZoom(), mZoomRatios, new ZoomChangeListener());
458d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
459d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
460c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu    public void animateFlash() {
4611dfe7828fd60741b9752553af3ee439c04e758a0Doris Liu        mController.startPreCaptureAnimation();
462c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu    }
463c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu
464d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public boolean onBackPressed() {
465d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        // In image capture mode, back button should:
466d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        // 1) if there is any popup, dismiss them, 2) otherwise, get out of
467d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        // image capture
468d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        if (mController.isImageCaptureIntent()) {
469c3679c0961521165499380c77344acc69072b2acDoris Liu            mController.onCaptureCancelled();
470d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            return true;
471d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        } else if (!mController.isCameraIdle()) {
472d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            // ignore backs while we're taking a picture
473d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            return true;
474d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        } else {
475c3679c0961521165499380c77344acc69072b2acDoris Liu            return false;
476d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
477d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
478d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
47936e56fba281292255a01ee00b4bee067fa09ab59Doris Liu    protected void showCapturedImageForReview(byte[] jpegData, int orientation, boolean mirror) {
48036e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        mDecodeTaskForReview = new DecodeImageForReview(jpegData, orientation, mirror);
48136e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        mDecodeTaskForReview.execute();
4824efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren
4834efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        mActivity.getCameraAppUI().transitionToIntentReviewLayout();
484d31cdfeb1035df8ba939e877031769f0df247aa6Doris Liu        pauseFaceDetection();
485d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
486d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
487d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    protected void hidePostCaptureAlert() {
48836e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        if (mDecodeTaskForReview != null) {
48936e56fba281292255a01ee00b4bee067fa09ab59Doris Liu            mDecodeTaskForReview.cancel(true);
49036e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        }
491d31cdfeb1035df8ba939e877031769f0df247aa6Doris Liu        resumeFaceDetection();
492d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
493d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
494d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void setDisplayOrientation(int orientation) {
495d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        if (mFaceView != null) {
496d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            mFaceView.setDisplayOrientation(orientation);
497d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
498d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
499d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
500f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu    private class ZoomChangeListener implements PreviewOverlay.OnZoomChangedListener {
501d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        @Override
502d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        public void onZoomValueChanged(int index) {
503f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu            mController.onZoomChanged(index);
504d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
505d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
506d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        @Override
507d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        public void onZoomStart() {
508d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
509d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
510d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        @Override
511d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        public void onZoomEnd() {
512d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
513d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
514d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
5156432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    public void setSwipingEnabled(boolean enable) {
5166432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu        mActivity.setSwipingEnabled(enable);
517d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
518d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
519d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void onPause() {
5201d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        if (mFaceView != null) {
5211d943647c5b632588c4858ded04770e846341f1bSascha Haeberling            mFaceView.clear();
5221d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        }
523db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        if (mDialog != null) {
524db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            mDialog.dismiss();
525db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        }
526d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
527d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
528d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void clearFaces() {
5290744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        if (mFaceView != null) {
5300744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            mFaceView.clear();
5310744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        }
532d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
533d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
534d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void pauseFaceDetection() {
5351d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        if (mFaceView != null) {
5361d943647c5b632588c4858ded04770e846341f1bSascha Haeberling            mFaceView.pause();
5371d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        }
538d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
539d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
540d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void resumeFaceDetection() {
5411d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        if (mFaceView != null) {
5421d943647c5b632588c4858ded04770e846341f1bSascha Haeberling            mFaceView.resume();
5431d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        }
544d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
545d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
546d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void onStartFaceDetection(int orientation, boolean mirror) {
547d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu        if (mFaceView != null) {
548d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu            mFaceView.clear();
549d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu            mFaceView.setVisibility(View.VISIBLE);
550d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu            mFaceView.setDisplayOrientation(orientation);
551d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu            mFaceView.setMirror(mirror);
552d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu            mFaceView.resume();
553d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu        }
554d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
555d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
556d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    @Override
5579e76552adff6ecf8b8e4070ecd61699cb6d18269Angus Kong    public void onFaceDetection(Face[] faces, CameraManager.CameraProxy camera) {
558d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu        if (mFaceView != null) {
559d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu            mFaceView.setFaces(faces);
560d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu        }
561d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
562d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
563d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb}
564