PhotoUI.java revision 5a344964cb003525727c31d295ca3a592c245606
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.Face;
2737f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberlingimport android.os.AsyncTask;
281d943647c5b632588c4858ded04770e846341f1bSascha Haeberlingimport android.os.Build;
29f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liuimport android.view.GestureDetector;
30f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liuimport android.view.MotionEvent;
31d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport android.view.View;
32d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport android.view.ViewGroup;
33b4a2222950f627a39267636fba19649974cb8734Spike Spragueimport android.widget.FrameLayout;
34b4a2222950f627a39267636fba19649974cb8734Spike Spragueimport android.widget.ImageView;
35d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
36d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport com.android.camera.FocusOverlayManager.FocusUI;
375596b4c902dcb685928b43678f428746ca5ffd08Angus Kongimport com.android.camera.debug.Log;
386c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liuimport com.android.camera.ui.CountDownView;
39d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport com.android.camera.ui.FaceView;
40f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liuimport com.android.camera.ui.PreviewOverlay;
4106db742814dd635d100639f977fcfdc904deb778Doris Liuimport com.android.camera.ui.PreviewStatusListener;
42b50b5cbfbc0a67db6fc43373363b10381c9c61a3Angus Kongimport com.android.camera.util.CameraUtil;
43db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liuimport com.android.camera.widget.AspectRatioDialogLayout;
44db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liuimport com.android.camera.widget.AspectRatioSelector;
45db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liuimport com.android.camera.widget.LocationDialogLayout;
468e963a5a6016d246184ed65906f9d103e92b17e2Sascha Haeberlingimport com.android.camera2.R;
475a344964cb003525727c31d295ca3a592c245606Sol Boucherimport com.android.ex.camera2.portability.CameraCapabilities;
485a344964cb003525727c31d295ca3a592c245606Sol Boucherimport com.android.ex.camera2.portability.CameraAgent;
495a344964cb003525727c31d295ca3a592c245606Sol Boucherimport com.android.ex.camera2.portability.CameraSettings;
50b50b5cbfbc0a67db6fc43373363b10381c9c61a3Angus Kong
51b50b5cbfbc0a67db6fc43373363b10381c9c61a3Angus Kongimport java.util.List;
52d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
53482de029dc20e0a577388a602985fb31c3200309Doris Liupublic class PhotoUI implements PreviewStatusListener,
545a344964cb003525727c31d295ca3a592c245606Sol Boucher    CameraAgent.CameraFaceDetectionCallback, PreviewStatusListener.PreviewAreaChangedListener {
55d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
565596b4c902dcb685928b43678f428746ca5ffd08Angus Kong    private static final Log.Tag TAG = new Log.Tag("PhotoUI");
5737f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling    private static final int DOWN_SAMPLE_FACTOR = 4;
5870da918464276b110c43868caa272c97baadb89eDoris Liu    private static final float UNSET = 0f;
590f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague
60f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu    private final PreviewOverlay mPreviewOverlay;
61482de029dc20e0a577388a602985fb31c3200309Doris Liu    private final FocusUI mFocusUI;
62e2914fddcd6d4f78d812ef818d43364d9aa469d4Sascha Haeberling    private final CameraActivity mActivity;
63e2914fddcd6d4f78d812ef818d43364d9aa469d4Sascha Haeberling    private final PhotoController mController;
64d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
65e2914fddcd6d4f78d812ef818d43364d9aa469d4Sascha Haeberling    private final View mRootView;
66db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    private Dialog mDialog = null;
67d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
68d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu    // TODO: Remove face view logic if UX does not bring it back within a month.
691d943647c5b632588c4858ded04770e846341f1bSascha Haeberling    private final FaceView mFaceView = null;
7036e56fba281292255a01ee00b4bee067fa09ab59Doris Liu    private DecodeImageForReview mDecodeTaskForReview = null;
71d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
72d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    private int mZoomMax;
73d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    private List<Integer> mZoomRatios;
74d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
75d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    private int mPreviewWidth = 0;
76d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    private int mPreviewHeight = 0;
7770da918464276b110c43868caa272c97baadb89eDoris Liu    private float mAspectRatio = UNSET;
780744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
79b4a2222950f627a39267636fba19649974cb8734Spike Sprague    private ImageView mIntentReviewImageView;
80b4a2222950f627a39267636fba19649974cb8734Spike Sprague
8106db742814dd635d100639f977fcfdc904deb778Doris Liu    private final GestureDetector.OnGestureListener mPreviewGestureListener
8206db742814dd635d100639f977fcfdc904deb778Doris Liu            = new GestureDetector.SimpleOnGestureListener() {
8306db742814dd635d100639f977fcfdc904deb778Doris Liu        @Override
8406db742814dd635d100639f977fcfdc904deb778Doris Liu        public boolean onSingleTapUp(MotionEvent ev) {
8506db742814dd635d100639f977fcfdc904deb778Doris Liu            mController.onSingleTapUp(null, (int) ev.getX(), (int) ev.getY());
8606db742814dd635d100639f977fcfdc904deb778Doris Liu            return true;
8706db742814dd635d100639f977fcfdc904deb778Doris Liu        }
8806db742814dd635d100639f977fcfdc904deb778Doris Liu    };
89db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    private final DialogInterface.OnDismissListener mOnDismissListener
90db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            = new DialogInterface.OnDismissListener() {
91db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        @Override
92db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        public void onDismiss(DialogInterface dialog) {
93db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            mDialog = null;
94db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        }
95db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    };
9608b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu    private Runnable mRunnableForNextFrame = null;
976c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    private CountDownView mCountdownView;
980744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
9906db742814dd635d100639f977fcfdc904deb778Doris Liu    @Override
10006db742814dd635d100639f977fcfdc904deb778Doris Liu    public GestureDetector.OnGestureListener getGestureListener() {
10106db742814dd635d100639f977fcfdc904deb778Doris Liu        return mPreviewGestureListener;
10206db742814dd635d100639f977fcfdc904deb778Doris Liu    }
10306db742814dd635d100639f977fcfdc904deb778Doris Liu
1044a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu    @Override
105d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    public View.OnTouchListener getTouchListener() {
106d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        return null;
107d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    }
108d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren
109d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    @Override
1104a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu    public void onPreviewLayoutChanged(View v, int left, int top, int right,
1114a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu            int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
1124a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu        int width = right - left;
1134a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu        int height = bottom - top;
1144a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu        if (mPreviewWidth != width || mPreviewHeight != height) {
1154a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu            mPreviewWidth = width;
1164a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu            mPreviewHeight = height;
117d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
1184a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu    }
119d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
12070da918464276b110c43868caa272c97baadb89eDoris Liu    @Override
12170da918464276b110c43868caa272c97baadb89eDoris Liu    public boolean shouldAutoAdjustTransformMatrixOnLayout() {
12270da918464276b110c43868caa272c97baadb89eDoris Liu        return true;
12370da918464276b110c43868caa272c97baadb89eDoris Liu    }
12470da918464276b110c43868caa272c97baadb89eDoris Liu
12570da918464276b110c43868caa272c97baadb89eDoris Liu    @Override
12670da918464276b110c43868caa272c97baadb89eDoris Liu    public boolean shouldAutoAdjustBottomBar() {
12770da918464276b110c43868caa272c97baadb89eDoris Liu        return true;
12870da918464276b110c43868caa272c97baadb89eDoris Liu    }
12970da918464276b110c43868caa272c97baadb89eDoris Liu
13011ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu    @Override
13111ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu    public void onPreviewFlipped() {
13211ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu        mController.updateCameraOrientation();
13311ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu    }
13411ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu
13508b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu    /**
13608b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu     * Sets the runnable to run when the next frame comes in.
13708b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu     */
13808b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu    public void setRunnableForNextFrame(Runnable runnable) {
13908b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu        mRunnableForNextFrame = runnable;
14008b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu    }
14108b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu
1426c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    /**
1436c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu     * Starts the countdown timer.
1446c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu     *
1456c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu     * @param sec seconds to countdown
1466c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu     */
1476c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    public void startCountdown(int sec) {
1486c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu        mCountdownView.startCountDown(sec);
1496c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    }
1506c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu
1516c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    /**
1526c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu     * Sets a listener that gets notified when the countdown is finished.
1536c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu     */
1546c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    public void setCountdownFinishedListener(CountDownView.OnCountDownStatusListener listener) {
1556c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu        mCountdownView.setCountDownStatusListener(listener);
1566c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    }
1576c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu
1586c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    /**
1596c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu     * Returns whether the countdown is on-going.
1606c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu     */
1616c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    public boolean isCountingDown() {
1626c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu        return mCountdownView.isCountingDown();
1636c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    }
1646c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu
1656c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    /**
1666c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu     * Cancels the on-going countdown, if any.
1676c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu     */
1686c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    public void cancelCountDown() {
1696c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu        mCountdownView.cancelCountDown();
1706c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    }
1716c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu
1726c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    @Override
1736c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    public void onPreviewAreaChanged(RectF previewArea) {
1746c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu        if (mFaceView != null) {
1756c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu            mFaceView.onPreviewAreaChanged(previewArea);
1766c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu        }
1776c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu        mCountdownView.onPreviewAreaChanged(previewArea);
1786c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    }
1796c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu
18036e56fba281292255a01ee00b4bee067fa09ab59Doris Liu    private class DecodeTask extends AsyncTask<Void, Void, Bitmap> {
18137f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling        private final byte [] mData;
182e2914fddcd6d4f78d812ef818d43364d9aa469d4Sascha Haeberling        private final int mOrientation;
183e2914fddcd6d4f78d812ef818d43364d9aa469d4Sascha Haeberling        private final boolean mMirror;
184c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu
18529da2db13029f8896018836693139a05d1139362Doris Liu        public DecodeTask(byte[] data, int orientation, boolean mirror) {
18637f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling            mData = data;
187ce2acbcb77225b6d429a23e00f69aadde8c2378bDoris Liu            mOrientation = orientation;
18829da2db13029f8896018836693139a05d1139362Doris Liu            mMirror = mirror;
189c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu        }
190c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu
191c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu        @Override
19236e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        protected Bitmap doInBackground(Void... params) {
19337f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling            // Decode image in background.
194ce2acbcb77225b6d429a23e00f69aadde8c2378bDoris Liu            Bitmap bitmap = CameraUtil.downSample(mData, DOWN_SAMPLE_FACTOR);
19529da2db13029f8896018836693139a05d1139362Doris Liu            if (mOrientation != 0 || mMirror) {
196ce2acbcb77225b6d429a23e00f69aadde8c2378bDoris Liu                Matrix m = new Matrix();
19729da2db13029f8896018836693139a05d1139362Doris Liu                if (mMirror) {
19829da2db13029f8896018836693139a05d1139362Doris Liu                    // Flip horizontally
19929da2db13029f8896018836693139a05d1139362Doris Liu                    m.setScale(-1f, 1f);
20029da2db13029f8896018836693139a05d1139362Doris Liu                }
201cec75e408a2d451b90bac5f06e10906ffcafff33Andy Huibers                m.preRotate(mOrientation);
202ce2acbcb77225b6d429a23e00f69aadde8c2378bDoris Liu                return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m,
203ce2acbcb77225b6d429a23e00f69aadde8c2378bDoris Liu                        false);
204ce2acbcb77225b6d429a23e00f69aadde8c2378bDoris Liu            }
205ce2acbcb77225b6d429a23e00f69aadde8c2378bDoris Liu            return bitmap;
20637f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling        }
20737f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling    }
208c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu
20936e56fba281292255a01ee00b4bee067fa09ab59Doris Liu    private class DecodeImageForReview extends DecodeTask {
21036e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        public DecodeImageForReview(byte[] data, int orientation, boolean mirror) {
21136e56fba281292255a01ee00b4bee067fa09ab59Doris Liu            super(data, orientation, mirror);
21236e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        }
21336e56fba281292255a01ee00b4bee067fa09ab59Doris Liu
21436e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        @Override
21536e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        protected void onPostExecute(Bitmap bitmap) {
21636e56fba281292255a01ee00b4bee067fa09ab59Doris Liu            if (isCancelled()) {
21736e56fba281292255a01ee00b4bee067fa09ab59Doris Liu                return;
21836e56fba281292255a01ee00b4bee067fa09ab59Doris Liu            }
219b4a2222950f627a39267636fba19649974cb8734Spike Sprague
220b4a2222950f627a39267636fba19649974cb8734Spike Sprague            mIntentReviewImageView.setImageBitmap(bitmap);
221b4a2222950f627a39267636fba19649974cb8734Spike Sprague            showIntentReviewImageView();
222b4a2222950f627a39267636fba19649974cb8734Spike Sprague
22336e56fba281292255a01ee00b4bee067fa09ab59Doris Liu            mDecodeTaskForReview = null;
22436e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        }
22536e56fba281292255a01ee00b4bee067fa09ab59Doris Liu    }
22636e56fba281292255a01ee00b4bee067fa09ab59Doris Liu
227d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public PhotoUI(CameraActivity activity, PhotoController controller, View parent) {
228d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        mActivity = activity;
229d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        mController = controller;
230d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        mRootView = parent;
231d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
232f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        ViewGroup moduleRoot = (ViewGroup) mRootView.findViewById(R.id.module_layout);
233d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        mActivity.getLayoutInflater().inflate(R.layout.photo_module,
234e2914fddcd6d4f78d812ef818d43364d9aa469d4Sascha Haeberling                 moduleRoot, true);
235d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        initIndicators();
236482de029dc20e0a577388a602985fb31c3200309Doris Liu        mFocusUI = (FocusUI) mRootView.findViewById(R.id.focus_overlay);
237f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu        mPreviewOverlay = (PreviewOverlay) mRootView.findViewById(R.id.preview_overlay);
2386c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu        mCountdownView = (CountDownView) mRootView.findViewById(R.id.count_down_view);
239b4a2222950f627a39267636fba19649974cb8734Spike Sprague
240b4a2222950f627a39267636fba19649974cb8734Spike Sprague        if (mController.isImageCaptureIntent()) {
241b4a2222950f627a39267636fba19649974cb8734Spike Sprague            createIntentReviewImageView();
242b4a2222950f627a39267636fba19649974cb8734Spike Sprague        }
243b4a2222950f627a39267636fba19649974cb8734Spike Sprague    }
244b4a2222950f627a39267636fba19649974cb8734Spike Sprague
245b4a2222950f627a39267636fba19649974cb8734Spike Sprague    private void createIntentReviewImageView() {
246b4a2222950f627a39267636fba19649974cb8734Spike Sprague        ViewGroup parentViewGroup = (ViewGroup) mRootView;
247b4a2222950f627a39267636fba19649974cb8734Spike Sprague        mIntentReviewImageView = (ImageView) mActivity.getLayoutInflater()
248b4a2222950f627a39267636fba19649974cb8734Spike Sprague            .inflate(R.layout.intent_review_imageview, parentViewGroup, false);
249b4a2222950f627a39267636fba19649974cb8734Spike Sprague        parentViewGroup.addView(mIntentReviewImageView);
250b4a2222950f627a39267636fba19649974cb8734Spike Sprague        mIntentReviewImageView.bringToFront();
251b4a2222950f627a39267636fba19649974cb8734Spike Sprague
252b4a2222950f627a39267636fba19649974cb8734Spike Sprague        mActivity.getCameraAppUI().addPreviewAreaChangedListener(
253b4a2222950f627a39267636fba19649974cb8734Spike Sprague                new PreviewStatusListener.PreviewAreaChangedListener() {
254b4a2222950f627a39267636fba19649974cb8734Spike Sprague                    @Override
255b4a2222950f627a39267636fba19649974cb8734Spike Sprague                    public void onPreviewAreaChanged(RectF previewArea) {
256b4a2222950f627a39267636fba19649974cb8734Spike Sprague                        FrameLayout.LayoutParams params =
257b4a2222950f627a39267636fba19649974cb8734Spike Sprague                            (FrameLayout.LayoutParams) mIntentReviewImageView.getLayoutParams();
258b4a2222950f627a39267636fba19649974cb8734Spike Sprague                        params.width = (int) previewArea.width();
259b4a2222950f627a39267636fba19649974cb8734Spike Sprague                        params.height = (int) previewArea.height();
260b4a2222950f627a39267636fba19649974cb8734Spike Sprague                        params.setMargins((int) previewArea.left, (int) previewArea.top, 0, 0);
261b4a2222950f627a39267636fba19649974cb8734Spike Sprague                        mIntentReviewImageView.setLayoutParams(params);
262b4a2222950f627a39267636fba19649974cb8734Spike Sprague                    }
263b4a2222950f627a39267636fba19649974cb8734Spike Sprague                });
264b4a2222950f627a39267636fba19649974cb8734Spike Sprague    }
265b4a2222950f627a39267636fba19649974cb8734Spike Sprague
266b4a2222950f627a39267636fba19649974cb8734Spike Sprague    /**
267b4a2222950f627a39267636fba19649974cb8734Spike Sprague     * Show the image review over the live preview for intent captures.
268b4a2222950f627a39267636fba19649974cb8734Spike Sprague     */
269b4a2222950f627a39267636fba19649974cb8734Spike Sprague    public void showIntentReviewImageView() {
270b4a2222950f627a39267636fba19649974cb8734Spike Sprague        if (mIntentReviewImageView != null) {
271b4a2222950f627a39267636fba19649974cb8734Spike Sprague            mIntentReviewImageView.setVisibility(View.VISIBLE);
272b4a2222950f627a39267636fba19649974cb8734Spike Sprague        }
2736432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    }
2746432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu
275b4a2222950f627a39267636fba19649974cb8734Spike Sprague    /**
276b4a2222950f627a39267636fba19649974cb8734Spike Sprague     * Hide the image review over the live preview for intent captures.
277b4a2222950f627a39267636fba19649974cb8734Spike Sprague     */
278b4a2222950f627a39267636fba19649974cb8734Spike Sprague    public void hideIntentReviewImageView() {
279b4a2222950f627a39267636fba19649974cb8734Spike Sprague        if (mIntentReviewImageView != null) {
280b4a2222950f627a39267636fba19649974cb8734Spike Sprague            mIntentReviewImageView.setVisibility(View.INVISIBLE);
281b4a2222950f627a39267636fba19649974cb8734Spike Sprague        }
282b4a2222950f627a39267636fba19649974cb8734Spike Sprague    }
283b4a2222950f627a39267636fba19649974cb8734Spike Sprague
284b4a2222950f627a39267636fba19649974cb8734Spike Sprague
285482de029dc20e0a577388a602985fb31c3200309Doris Liu    public FocusUI getFocusUI() {
286482de029dc20e0a577388a602985fb31c3200309Doris Liu        return mFocusUI;
287482de029dc20e0a577388a602985fb31c3200309Doris Liu    }
288482de029dc20e0a577388a602985fb31c3200309Doris Liu
289d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu    public void updatePreviewAspectRatio(float aspectRatio) {
290d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu        if (aspectRatio <= 0) {
291d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu            Log.e(TAG, "Invalid aspect ratio: " + aspectRatio);
292d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu            return;
293d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu        }
294d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu        if (aspectRatio < 1f) {
295d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu            aspectRatio = 1f / aspectRatio;
296d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu        }
297d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu
298d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu        if (mAspectRatio != aspectRatio) {
299d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu            mAspectRatio = aspectRatio;
300d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu            // Update transform matrix with the new aspect ratio.
30170da918464276b110c43868caa272c97baadb89eDoris Liu            mController.updatePreviewAspectRatio(mAspectRatio);
302d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu        }
303d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu    }
304d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu
305dcccc510652b835fdbd39310a07849af8203052aAngus Kong    @Override
3066432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
307d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        mController.onPreviewUIReady();
3086432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    }
309d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
310dcccc510652b835fdbd39310a07849af8203052aAngus Kong    @Override
3116432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
3126432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu        // Ignored, Camera does all the work for us
3136432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    }
3146432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu
315dcccc510652b835fdbd39310a07849af8203052aAngus Kong    @Override
3166432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
317d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        mController.onPreviewUIDestroyed();
318d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        return true;
3196432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    }
3206432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu
3217b265a6b2f55c6ae7afc30e63ba324c4084a5d8eztenghui    @Override
3226432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
32308b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu        if (mRunnableForNextFrame != null) {
32408b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu            mRootView.post(mRunnableForNextFrame);
32508b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu            mRunnableForNextFrame = null;
32608b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu        }
327d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
328d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
329d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public View getRootView() {
330d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        return mRootView;
331d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
332d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
333d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    private void initIndicators() {
3340744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        // TODO init toggle buttons on bottom bar here
335d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
336d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
3376607dae6c4d1ee5bbf572695c2042d4d9129a730Angus Kong    public void onCameraOpened(CameraCapabilities capabilities, CameraSettings settings) {
3386607dae6c4d1ee5bbf572695c2042d4d9129a730Angus Kong        initializeZoom(capabilities, settings);
339eb3134f6ecc42f7d98625ca2c0ddfb06c9f07c43Spike Sprague    }
340eb3134f6ecc42f7d98625ca2c0ddfb06c9f07c43Spike Sprague
3410a6a8d8e4e1c9796aac606379a42970cdffb8911Erin Dahlgren    public void animateCapture(final byte[] jpegData, int orientation, boolean mirror) {
3420a6a8d8e4e1c9796aac606379a42970cdffb8911Erin Dahlgren        // Decode jpeg byte array and then animate the jpeg
3430a6a8d8e4e1c9796aac606379a42970cdffb8911Erin Dahlgren        DecodeTask task = new DecodeTask(jpegData, orientation, mirror);
3440a6a8d8e4e1c9796aac606379a42970cdffb8911Erin Dahlgren        task.execute();
345eb3134f6ecc42f7d98625ca2c0ddfb06c9f07c43Spike Sprague    }
346d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
347d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    // called from onResume but only the first time
348ffbc43c3dd3c94a968a41431fb07645a13696c4aKevin Gabayan    public void initializeFirstTime() {
3490744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
350d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
351d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
352d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    // called from onResume every other time
3536607dae6c4d1ee5bbf572695c2042d4d9129a730Angus Kong    public void initializeSecondTime(CameraCapabilities capabilities, CameraSettings settings) {
3546607dae6c4d1ee5bbf572695c2042d4d9129a730Angus Kong        initializeZoom(capabilities, settings);
355d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        if (mController.isImageCaptureIntent()) {
356d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            hidePostCaptureAlert();
357d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
358d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
359d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
360db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    public void showLocationAndAspectRatioDialog(
361db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            final PhotoModule.LocationDialogCallback locationCallback,
362db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            final PhotoModule.AspectRatioDialogCallback aspectRatioDialogCallback) {
363db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        setDialog(new Dialog(mActivity,
364db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                android.R.style.Theme_Black_NoTitleBar_Fullscreen));
365db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        final LocationDialogLayout locationDialogLayout = (LocationDialogLayout) mActivity
366db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                .getLayoutInflater().inflate(R.layout.location_dialog_layout, null);
367db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        locationDialogLayout.setLocationTaggingSelectionListener(
368db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                new LocationDialogLayout.LocationTaggingSelectionListener() {
369db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            @Override
370db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            public void onLocationTaggingSelected(boolean selected) {
371db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                // Update setting.
372db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                locationCallback.onLocationTaggingSelected(selected);
3731d943647c5b632588c4858ded04770e846341f1bSascha Haeberling
3741d943647c5b632588c4858ded04770e846341f1bSascha Haeberling                if (showAspectRatioDialogOnThisDevice()) {
3751d943647c5b632588c4858ded04770e846341f1bSascha Haeberling                    // Go to next page.
3761d943647c5b632588c4858ded04770e846341f1bSascha Haeberling                    showAspectRatioDialog(aspectRatioDialogCallback, mDialog);
3771d943647c5b632588c4858ded04770e846341f1bSascha Haeberling                } else {
3781d943647c5b632588c4858ded04770e846341f1bSascha Haeberling                    // If we don't want to show the aspect ratio dialog,
3791d943647c5b632588c4858ded04770e846341f1bSascha Haeberling                    // dismiss the dialog right after the user chose the
3801d943647c5b632588c4858ded04770e846341f1bSascha Haeberling                    // location setting.
3811d943647c5b632588c4858ded04770e846341f1bSascha Haeberling                    if (mDialog != null) {
3821d943647c5b632588c4858ded04770e846341f1bSascha Haeberling                        mDialog.dismiss();
3831d943647c5b632588c4858ded04770e846341f1bSascha Haeberling                    }
3841d943647c5b632588c4858ded04770e846341f1bSascha Haeberling                }
385db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            }
386db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        });
387db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        mDialog.setContentView(locationDialogLayout, new ViewGroup.LayoutParams(
388db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
389db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        mDialog.show();
390db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    }
391db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu
392db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    /**
393db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu     * Dismisses previous dialog if any, sets current dialog to the given dialog,
394db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu     * and set the on dismiss listener for the given dialog.
395db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu     * @param dialog dialog to show
396db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu     */
397db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    private void setDialog(Dialog dialog) {
398db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        if (mDialog != null) {
399db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            mDialog.setOnDismissListener(null);
400db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            mDialog.dismiss();
401db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        }
402db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        mDialog = dialog;
403db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        if (mDialog != null) {
404db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            mDialog.setOnDismissListener(mOnDismissListener);
405db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        }
406db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    }
407db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu
408db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    public void showAspectRatioDialog(final PhotoModule.AspectRatioDialogCallback callback) {
4091d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        if (showAspectRatioDialogOnThisDevice()) {
4101d943647c5b632588c4858ded04770e846341f1bSascha Haeberling            setDialog(new Dialog(mActivity, android.R.style.Theme_Black_NoTitleBar_Fullscreen));
4111d943647c5b632588c4858ded04770e846341f1bSascha Haeberling            showAspectRatioDialog(callback, mDialog);
4121d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        }
413db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    }
414db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu
415db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    private void showAspectRatioDialog(final PhotoModule.AspectRatioDialogCallback callback,
416db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            final Dialog aspectRatioDialog) {
417db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        if (aspectRatioDialog == null) {
418db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            Log.e(TAG, "Dialog for aspect ratio is null.");
419db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            return;
420db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        }
421db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        final AspectRatioDialogLayout aspectRatioDialogLayout =
422db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                (AspectRatioDialogLayout) mActivity
423db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                .getLayoutInflater().inflate(R.layout.aspect_ratio_dialog_layout, null);
424db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        aspectRatioDialogLayout.initialize(
425db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                new AspectRatioDialogLayout.AspectRatioChangedListener() {
426db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                    @Override
427db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                    public void onAspectRatioChanged(AspectRatioSelector.AspectRatio aspectRatio) {
428db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                        // callback to set picture size.
42908b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu                        callback.onAspectRatioSelected(aspectRatio, new Runnable() {
43008b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu                            @Override
43108b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu                            public void run() {
43208b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu                                if (mDialog != null) {
43308b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu                                    mDialog.dismiss();
43408b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu                                }
43508b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu                            }
43608b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu                        });
437db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                    }
438e811b29f6707a6ea8f066e6f5b9cb0fc99d2dcd6Sascha Haeberling                }, callback.getCurrentAspectRatio());
439db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        aspectRatioDialog.setContentView(aspectRatioDialogLayout, new ViewGroup.LayoutParams(
440db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
441db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        aspectRatioDialog.show();
4426a83d528b09c55ade6ad44b82c81d4476ac57441Doris Liu    }
4436a83d528b09c55ade6ad44b82c81d4476ac57441Doris Liu
4441d943647c5b632588c4858ded04770e846341f1bSascha Haeberling    /**
4451d943647c5b632588c4858ded04770e846341f1bSascha Haeberling     * @return Whether this is a device that we should show the aspect ratio
4461d943647c5b632588c4858ded04770e846341f1bSascha Haeberling     *         intro dialog on.
4471d943647c5b632588c4858ded04770e846341f1bSascha Haeberling     */
4481d943647c5b632588c4858ded04770e846341f1bSascha Haeberling    private boolean showAspectRatioDialogOnThisDevice() {
4491d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        // We only want to show that dialog on N4 and N5
4501d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        return "hammerhead".equals(Build.DEVICE) || "mako".equals(Build.DEVICE);
4511d943647c5b632588c4858ded04770e846341f1bSascha Haeberling    }
4521d943647c5b632588c4858ded04770e846341f1bSascha Haeberling
4536607dae6c4d1ee5bbf572695c2042d4d9129a730Angus Kong    public void initializeZoom(CameraCapabilities capabilities, CameraSettings settings) {
4546607dae6c4d1ee5bbf572695c2042d4d9129a730Angus Kong        if ((capabilities == null) || settings == null ||
4556607dae6c4d1ee5bbf572695c2042d4d9129a730Angus Kong                !capabilities.supports(CameraCapabilities.Feature.ZOOM)) {
4561d943647c5b632588c4858ded04770e846341f1bSascha Haeberling            return;
4571d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        }
4586607dae6c4d1ee5bbf572695c2042d4d9129a730Angus Kong        mZoomMax = capabilities.getMaxZoomIndex();
4596607dae6c4d1ee5bbf572695c2042d4d9129a730Angus Kong        mZoomRatios = capabilities.getZoomRatioList();
460d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        // Currently we use immediate zoom for fast zooming to get better UX and
461d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        // there is no plan to take advantage of the smooth zoom.
462f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu        // TODO: Need to setup a path to AppUI to do this
4636607dae6c4d1ee5bbf572695c2042d4d9129a730Angus Kong        mPreviewOverlay.setupZoom(mZoomMax, settings.getCurrentZoomIndex(), mZoomRatios,
4646607dae6c4d1ee5bbf572695c2042d4d9129a730Angus Kong                new ZoomChangeListener());
465d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
466d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
467c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu    public void animateFlash() {
4681dfe7828fd60741b9752553af3ee439c04e758a0Doris Liu        mController.startPreCaptureAnimation();
469c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu    }
470c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu
471d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public boolean onBackPressed() {
472d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        // In image capture mode, back button should:
473d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        // 1) if there is any popup, dismiss them, 2) otherwise, get out of
474d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        // image capture
475d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        if (mController.isImageCaptureIntent()) {
476c3679c0961521165499380c77344acc69072b2acDoris Liu            mController.onCaptureCancelled();
477d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            return true;
478d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        } else if (!mController.isCameraIdle()) {
479d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            // ignore backs while we're taking a picture
480d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            return true;
481d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        } else {
482c3679c0961521165499380c77344acc69072b2acDoris Liu            return false;
483d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
484d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
485d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
48636e56fba281292255a01ee00b4bee067fa09ab59Doris Liu    protected void showCapturedImageForReview(byte[] jpegData, int orientation, boolean mirror) {
48736e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        mDecodeTaskForReview = new DecodeImageForReview(jpegData, orientation, mirror);
48836e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        mDecodeTaskForReview.execute();
4894efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren
4904efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        mActivity.getCameraAppUI().transitionToIntentReviewLayout();
491d31cdfeb1035df8ba939e877031769f0df247aa6Doris Liu        pauseFaceDetection();
492d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
493d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
494d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    protected void hidePostCaptureAlert() {
49536e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        if (mDecodeTaskForReview != null) {
49636e56fba281292255a01ee00b4bee067fa09ab59Doris Liu            mDecodeTaskForReview.cancel(true);
49736e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        }
498d31cdfeb1035df8ba939e877031769f0df247aa6Doris Liu        resumeFaceDetection();
499d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
500d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
501d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void setDisplayOrientation(int orientation) {
502d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        if (mFaceView != null) {
503d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            mFaceView.setDisplayOrientation(orientation);
504d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
505d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
506d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
507f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu    private class ZoomChangeListener implements PreviewOverlay.OnZoomChangedListener {
508d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        @Override
509d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        public void onZoomValueChanged(int index) {
510f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu            mController.onZoomChanged(index);
511d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
512d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
513d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        @Override
514d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        public void onZoomStart() {
515d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
516d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
517d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        @Override
518d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        public void onZoomEnd() {
519d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
520d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
521d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
5226432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    public void setSwipingEnabled(boolean enable) {
5236432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu        mActivity.setSwipingEnabled(enable);
524d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
525d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
526d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void onPause() {
5271d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        if (mFaceView != null) {
5281d943647c5b632588c4858ded04770e846341f1bSascha Haeberling            mFaceView.clear();
5291d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        }
530db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        if (mDialog != null) {
531db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            mDialog.dismiss();
532db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        }
533d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
534d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
535d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void clearFaces() {
5360744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        if (mFaceView != null) {
5370744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            mFaceView.clear();
5380744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        }
539d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
540d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
541d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void pauseFaceDetection() {
5421d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        if (mFaceView != null) {
5431d943647c5b632588c4858ded04770e846341f1bSascha Haeberling            mFaceView.pause();
5441d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        }
545d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
546d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
547d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void resumeFaceDetection() {
5481d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        if (mFaceView != null) {
5491d943647c5b632588c4858ded04770e846341f1bSascha Haeberling            mFaceView.resume();
5501d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        }
551d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
552d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
553d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void onStartFaceDetection(int orientation, boolean mirror) {
554d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu        if (mFaceView != null) {
555d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu            mFaceView.clear();
556d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu            mFaceView.setVisibility(View.VISIBLE);
557d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu            mFaceView.setDisplayOrientation(orientation);
558d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu            mFaceView.setMirror(mirror);
559d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu            mFaceView.resume();
560d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu        }
561d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
562d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
563d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    @Override
5645a344964cb003525727c31d295ca3a592c245606Sol Boucher    public void onFaceDetection(Face[] faces, CameraAgent.CameraProxy camera) {
565d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu        if (mFaceView != null) {
566d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu            mFaceView.setFaces(faces);
567d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu        }
568d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
569d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
570d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb}
571