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;
226432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liuimport android.graphics.Matrix;
236c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liuimport android.graphics.RectF;
246432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liuimport android.graphics.SurfaceTexture;
25d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport android.hardware.Camera.Face;
2637f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberlingimport android.os.AsyncTask;
271d943647c5b632588c4858ded04770e846341f1bSascha Haeberlingimport android.os.Build;
28f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liuimport android.view.GestureDetector;
29f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liuimport android.view.MotionEvent;
30d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport android.view.View;
31d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport android.view.ViewGroup;
32b4a2222950f627a39267636fba19649974cb8734Spike Spragueimport android.widget.FrameLayout;
33b4a2222950f627a39267636fba19649974cb8734Spike Spragueimport android.widget.ImageView;
34d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
35d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport com.android.camera.FocusOverlayManager.FocusUI;
3662b4c3c0da3abd397b3790820359927784c50bc2Andy Huibersimport com.android.camera.debug.DebugPropertyHelper;
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;
422631a15a37b890f4ee720c5a4bbe3e654524deb6Alan Newbergerimport com.android.camera.util.ApiHelper;
43b50b5cbfbc0a67db6fc43373363b10381c9c61a3Angus Kongimport com.android.camera.util.CameraUtil;
442631a15a37b890f4ee720c5a4bbe3e654524deb6Alan Newbergerimport com.android.camera.util.GservicesHelper;
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;
495a344964cb003525727c31d295ca3a592c245606Sol Boucherimport com.android.ex.camera2.portability.CameraAgent;
504c1bffecc94cedf56d188eca40bd65a854746413Sascha Haeberlingimport com.android.ex.camera2.portability.CameraCapabilities;
515a344964cb003525727c31d295ca3a592c245606Sol Boucherimport com.android.ex.camera2.portability.CameraSettings;
52b50b5cbfbc0a67db6fc43373363b10381c9c61a3Angus Kong
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.
6962b4c3c0da3abd397b3790820359927784c50bc2Andy Huibers    private final FaceView mFaceView;
7036e56fba281292255a01ee00b4bee067fa09ab59Doris Liu    private DecodeImageForReview mDecodeTaskForReview = null;
71d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
722192fbaaf598d4440a8d537a70095ea56bc9a5ebSol Boucher    private float mZoomMax;
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;
964c1bffecc94cedf56d188eca40bd65a854746413Sascha Haeberling    private final 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);
23862b4c3c0da3abd397b3790820359927784c50bc2Andy Huibers        // Show faces if we are in debug mode.
23962b4c3c0da3abd397b3790820359927784c50bc2Andy Huibers        if (DebugPropertyHelper.showCaptureDebugUI()) {
24062b4c3c0da3abd397b3790820359927784c50bc2Andy Huibers            mFaceView = (FaceView) mRootView.findViewById(R.id.face_view);
24162b4c3c0da3abd397b3790820359927784c50bc2Andy Huibers        } else {
24262b4c3c0da3abd397b3790820359927784c50bc2Andy Huibers            mFaceView = null;
24362b4c3c0da3abd397b3790820359927784c50bc2Andy Huibers        }
244b4a2222950f627a39267636fba19649974cb8734Spike Sprague
245b4a2222950f627a39267636fba19649974cb8734Spike Sprague        if (mController.isImageCaptureIntent()) {
24602b9b9af097ac7886ec1d23392cd87c9fbcb186fSpike Sprague            initIntentReviewImageView();
247b4a2222950f627a39267636fba19649974cb8734Spike Sprague        }
248b4a2222950f627a39267636fba19649974cb8734Spike Sprague    }
249b4a2222950f627a39267636fba19649974cb8734Spike Sprague
25002b9b9af097ac7886ec1d23392cd87c9fbcb186fSpike Sprague    private void initIntentReviewImageView() {
25102b9b9af097ac7886ec1d23392cd87c9fbcb186fSpike Sprague        mIntentReviewImageView = (ImageView) mRootView.findViewById(R.id.intent_review_imageview);
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
4084c1bffecc94cedf56d188eca40bd65a854746413Sascha Haeberling    /**
4094c1bffecc94cedf56d188eca40bd65a854746413Sascha Haeberling     * @return Whether the dialog was shown.
4104c1bffecc94cedf56d188eca40bd65a854746413Sascha Haeberling     */
4114c1bffecc94cedf56d188eca40bd65a854746413Sascha Haeberling    public boolean showAspectRatioDialog(final PhotoModule.AspectRatioDialogCallback callback) {
4121d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        if (showAspectRatioDialogOnThisDevice()) {
4131d943647c5b632588c4858ded04770e846341f1bSascha Haeberling            setDialog(new Dialog(mActivity, android.R.style.Theme_Black_NoTitleBar_Fullscreen));
4141d943647c5b632588c4858ded04770e846341f1bSascha Haeberling            showAspectRatioDialog(callback, mDialog);
4154c1bffecc94cedf56d188eca40bd65a854746413Sascha Haeberling            return true;
4164c1bffecc94cedf56d188eca40bd65a854746413Sascha Haeberling        } else {
4174c1bffecc94cedf56d188eca40bd65a854746413Sascha Haeberling            return false;
4181d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        }
419db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    }
420db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu
4214c1bffecc94cedf56d188eca40bd65a854746413Sascha Haeberling    private boolean showAspectRatioDialog(final PhotoModule.AspectRatioDialogCallback callback,
422db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            final Dialog aspectRatioDialog) {
423db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        if (aspectRatioDialog == null) {
424db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            Log.e(TAG, "Dialog for aspect ratio is null.");
4254c1bffecc94cedf56d188eca40bd65a854746413Sascha Haeberling            return false;
426db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        }
427db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        final AspectRatioDialogLayout aspectRatioDialogLayout =
428db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                (AspectRatioDialogLayout) mActivity
429db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                .getLayoutInflater().inflate(R.layout.aspect_ratio_dialog_layout, null);
430db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        aspectRatioDialogLayout.initialize(
431db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                new AspectRatioDialogLayout.AspectRatioChangedListener() {
432db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                    @Override
433db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                    public void onAspectRatioChanged(AspectRatioSelector.AspectRatio aspectRatio) {
434db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                        // callback to set picture size.
43508b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu                        callback.onAspectRatioSelected(aspectRatio, new Runnable() {
43608b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu                            @Override
43708b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu                            public void run() {
43808b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu                                if (mDialog != null) {
43908b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu                                    mDialog.dismiss();
44008b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu                                }
44108b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu                            }
44208b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu                        });
443db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                    }
444e811b29f6707a6ea8f066e6f5b9cb0fc99d2dcd6Sascha Haeberling                }, callback.getCurrentAspectRatio());
445db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        aspectRatioDialog.setContentView(aspectRatioDialogLayout, new ViewGroup.LayoutParams(
446db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
447db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        aspectRatioDialog.show();
4484c1bffecc94cedf56d188eca40bd65a854746413Sascha Haeberling        return true;
4496a83d528b09c55ade6ad44b82c81d4476ac57441Doris Liu    }
4506a83d528b09c55ade6ad44b82c81d4476ac57441Doris Liu
4511d943647c5b632588c4858ded04770e846341f1bSascha Haeberling    /**
4521d943647c5b632588c4858ded04770e846341f1bSascha Haeberling     * @return Whether this is a device that we should show the aspect ratio
4531d943647c5b632588c4858ded04770e846341f1bSascha Haeberling     *         intro dialog on.
4541d943647c5b632588c4858ded04770e846341f1bSascha Haeberling     */
4551d943647c5b632588c4858ded04770e846341f1bSascha Haeberling    private boolean showAspectRatioDialogOnThisDevice() {
4562631a15a37b890f4ee720c5a4bbe3e654524deb6Alan Newberger        // We only want to show that dialog on N4/N5/N6
4572631a15a37b890f4ee720c5a4bbe3e654524deb6Alan Newberger        // Don't show if using API2 portability, b/17462976
4582631a15a37b890f4ee720c5a4bbe3e654524deb6Alan Newberger        return !GservicesHelper.useCamera2ApiThroughPortabilityLayer(mActivity) &&
4592631a15a37b890f4ee720c5a4bbe3e654524deb6Alan Newberger                (ApiHelper.IS_NEXUS_4 || ApiHelper.IS_NEXUS_5 || ApiHelper.IS_NEXUS_6);
4601d943647c5b632588c4858ded04770e846341f1bSascha Haeberling    }
4611d943647c5b632588c4858ded04770e846341f1bSascha Haeberling
4626607dae6c4d1ee5bbf572695c2042d4d9129a730Angus Kong    public void initializeZoom(CameraCapabilities capabilities, CameraSettings settings) {
4636607dae6c4d1ee5bbf572695c2042d4d9129a730Angus Kong        if ((capabilities == null) || settings == null ||
4646607dae6c4d1ee5bbf572695c2042d4d9129a730Angus Kong                !capabilities.supports(CameraCapabilities.Feature.ZOOM)) {
4651d943647c5b632588c4858ded04770e846341f1bSascha Haeberling            return;
4661d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        }
4672192fbaaf598d4440a8d537a70095ea56bc9a5ebSol Boucher        mZoomMax = capabilities.getMaxZoomRatio();
468d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        // Currently we use immediate zoom for fast zooming to get better UX and
469d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        // there is no plan to take advantage of the smooth zoom.
470f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu        // TODO: Need to setup a path to AppUI to do this
4712192fbaaf598d4440a8d537a70095ea56bc9a5ebSol Boucher        mPreviewOverlay.setupZoom(mZoomMax, settings.getCurrentZoomRatio(),
4726607dae6c4d1ee5bbf572695c2042d4d9129a730Angus Kong                new ZoomChangeListener());
473d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
474d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
475c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu    public void animateFlash() {
4761dfe7828fd60741b9752553af3ee439c04e758a0Doris Liu        mController.startPreCaptureAnimation();
477c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu    }
478c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu
479d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public boolean onBackPressed() {
480d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        // In image capture mode, back button should:
481d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        // 1) if there is any popup, dismiss them, 2) otherwise, get out of
482d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        // image capture
483d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        if (mController.isImageCaptureIntent()) {
484c3679c0961521165499380c77344acc69072b2acDoris Liu            mController.onCaptureCancelled();
485d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            return true;
486d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        } else if (!mController.isCameraIdle()) {
487d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            // ignore backs while we're taking a picture
488d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            return true;
489d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        } else {
490c3679c0961521165499380c77344acc69072b2acDoris Liu            return false;
491d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
492d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
493d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
49436e56fba281292255a01ee00b4bee067fa09ab59Doris Liu    protected void showCapturedImageForReview(byte[] jpegData, int orientation, boolean mirror) {
49536e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        mDecodeTaskForReview = new DecodeImageForReview(jpegData, orientation, mirror);
49636e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        mDecodeTaskForReview.execute();
4974efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren
4984efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        mActivity.getCameraAppUI().transitionToIntentReviewLayout();
499d31cdfeb1035df8ba939e877031769f0df247aa6Doris Liu        pauseFaceDetection();
500d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
501d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
502d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    protected void hidePostCaptureAlert() {
50336e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        if (mDecodeTaskForReview != null) {
50436e56fba281292255a01ee00b4bee067fa09ab59Doris Liu            mDecodeTaskForReview.cancel(true);
50536e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        }
506d31cdfeb1035df8ba939e877031769f0df247aa6Doris Liu        resumeFaceDetection();
507d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
508d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
509d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void setDisplayOrientation(int orientation) {
510d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        if (mFaceView != null) {
511d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            mFaceView.setDisplayOrientation(orientation);
512d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
513d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
514d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
515f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu    private class ZoomChangeListener implements PreviewOverlay.OnZoomChangedListener {
516d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        @Override
5172192fbaaf598d4440a8d537a70095ea56bc9a5ebSol Boucher        public void onZoomValueChanged(float ratio) {
5182192fbaaf598d4440a8d537a70095ea56bc9a5ebSol Boucher            mController.onZoomChanged(ratio);
519d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
520d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
521d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        @Override
522d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        public void onZoomStart() {
523d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
524d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
525d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        @Override
526d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        public void onZoomEnd() {
527d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
528d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
529d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
5306432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    public void setSwipingEnabled(boolean enable) {
5316432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu        mActivity.setSwipingEnabled(enable);
532d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
533d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
534d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void onPause() {
5351d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        if (mFaceView != null) {
5361d943647c5b632588c4858ded04770e846341f1bSascha Haeberling            mFaceView.clear();
5371d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        }
538db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        if (mDialog != null) {
539db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            mDialog.dismiss();
540db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        }
5417351415ddfaf7f563a4a12c9204e6feb20fdf49dAlan Newberger        // recalculate aspect ratio when restarting.
5427351415ddfaf7f563a4a12c9204e6feb20fdf49dAlan Newberger        mAspectRatio = 0.0f;
543d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
544d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
545d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void clearFaces() {
5460744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        if (mFaceView != null) {
5470744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            mFaceView.clear();
5480744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        }
549d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
550d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
551d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void pauseFaceDetection() {
5521d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        if (mFaceView != null) {
5531d943647c5b632588c4858ded04770e846341f1bSascha Haeberling            mFaceView.pause();
5541d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        }
555d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
556d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
557d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void resumeFaceDetection() {
5581d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        if (mFaceView != null) {
5591d943647c5b632588c4858ded04770e846341f1bSascha Haeberling            mFaceView.resume();
5601d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        }
561d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
562d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
563d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void onStartFaceDetection(int orientation, boolean mirror) {
564d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu        if (mFaceView != null) {
565d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu            mFaceView.clear();
566d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu            mFaceView.setVisibility(View.VISIBLE);
567d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu            mFaceView.setDisplayOrientation(orientation);
568d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu            mFaceView.setMirror(mirror);
569d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu            mFaceView.resume();
570d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu        }
571d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
572d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
573d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    @Override
5745a344964cb003525727c31d295ca3a592c245606Sol Boucher    public void onFaceDetection(Face[] faces, CameraAgent.CameraProxy camera) {
575d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu        if (mFaceView != null) {
576d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu            mFaceView.setFaces(faces);
577d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu        }
578d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
579d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
580d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb}
581