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;
226c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liuimport android.graphics.RectF;
236432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liuimport android.graphics.SurfaceTexture;
24d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport android.hardware.Camera.Face;
2537f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberlingimport android.os.AsyncTask;
26f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liuimport android.view.GestureDetector;
27f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liuimport android.view.MotionEvent;
28d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport android.view.View;
29d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport android.view.ViewGroup;
30b4a2222950f627a39267636fba19649974cb8734Spike Spragueimport android.widget.FrameLayout;
31b4a2222950f627a39267636fba19649974cb8734Spike Spragueimport android.widget.ImageView;
32d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
3300a764a3b6d9072413d18b441c759d4a604223b4Senpo Huimport com.android.camera.captureintent.PictureDecoder;
3462b4c3c0da3abd397b3790820359927784c50bc2Andy Huibersimport com.android.camera.debug.DebugPropertyHelper;
355596b4c902dcb685928b43678f428746ca5ffd08Angus Kongimport com.android.camera.debug.Log;
366c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liuimport com.android.camera.ui.CountDownView;
37d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport com.android.camera.ui.FaceView;
38f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liuimport com.android.camera.ui.PreviewOverlay;
3906db742814dd635d100639f977fcfdc904deb778Doris Liuimport com.android.camera.ui.PreviewStatusListener;
40987ee64612e2510004fdf08536746c87234d01c1Paul Rohdeimport com.android.camera.ui.focus.FocusRing;
418e963a5a6016d246184ed65906f9d103e92b17e2Sascha Haeberlingimport com.android.camera2.R;
425a344964cb003525727c31d295ca3a592c245606Sol Boucherimport com.android.ex.camera2.portability.CameraAgent;
434c1bffecc94cedf56d188eca40bd65a854746413Sascha Haeberlingimport com.android.ex.camera2.portability.CameraCapabilities;
445a344964cb003525727c31d295ca3a592c245606Sol Boucherimport com.android.ex.camera2.portability.CameraSettings;
45b50b5cbfbc0a67db6fc43373363b10381c9c61a3Angus Kong
46482de029dc20e0a577388a602985fb31c3200309Doris Liupublic class PhotoUI implements PreviewStatusListener,
475a344964cb003525727c31d295ca3a592c245606Sol Boucher    CameraAgent.CameraFaceDetectionCallback, PreviewStatusListener.PreviewAreaChangedListener {
48d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
495596b4c902dcb685928b43678f428746ca5ffd08Angus Kong    private static final Log.Tag TAG = new Log.Tag("PhotoUI");
5037f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling    private static final int DOWN_SAMPLE_FACTOR = 4;
5170da918464276b110c43868caa272c97baadb89eDoris Liu    private static final float UNSET = 0f;
520f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague
53f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu    private final PreviewOverlay mPreviewOverlay;
54987ee64612e2510004fdf08536746c87234d01c1Paul Rohde    private final FocusRing mFocusRing;
55e2914fddcd6d4f78d812ef818d43364d9aa469d4Sascha Haeberling    private final CameraActivity mActivity;
56e2914fddcd6d4f78d812ef818d43364d9aa469d4Sascha Haeberling    private final PhotoController mController;
57d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
58e2914fddcd6d4f78d812ef818d43364d9aa469d4Sascha Haeberling    private final View mRootView;
59db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    private Dialog mDialog = null;
60d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
61d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu    // TODO: Remove face view logic if UX does not bring it back within a month.
6262b4c3c0da3abd397b3790820359927784c50bc2Andy Huibers    private final FaceView mFaceView;
6336e56fba281292255a01ee00b4bee067fa09ab59Doris Liu    private DecodeImageForReview mDecodeTaskForReview = null;
64d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
652192fbaaf598d4440a8d537a70095ea56bc9a5ebSol Boucher    private float mZoomMax;
66d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
67d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    private int mPreviewWidth = 0;
68d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    private int mPreviewHeight = 0;
6970da918464276b110c43868caa272c97baadb89eDoris Liu    private float mAspectRatio = UNSET;
700744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
71b4a2222950f627a39267636fba19649974cb8734Spike Sprague    private ImageView mIntentReviewImageView;
72b4a2222950f627a39267636fba19649974cb8734Spike Sprague
7306db742814dd635d100639f977fcfdc904deb778Doris Liu    private final GestureDetector.OnGestureListener mPreviewGestureListener
7406db742814dd635d100639f977fcfdc904deb778Doris Liu            = new GestureDetector.SimpleOnGestureListener() {
7506db742814dd635d100639f977fcfdc904deb778Doris Liu        @Override
7606db742814dd635d100639f977fcfdc904deb778Doris Liu        public boolean onSingleTapUp(MotionEvent ev) {
7706db742814dd635d100639f977fcfdc904deb778Doris Liu            mController.onSingleTapUp(null, (int) ev.getX(), (int) ev.getY());
7806db742814dd635d100639f977fcfdc904deb778Doris Liu            return true;
7906db742814dd635d100639f977fcfdc904deb778Doris Liu        }
8006db742814dd635d100639f977fcfdc904deb778Doris Liu    };
81db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    private final DialogInterface.OnDismissListener mOnDismissListener
82db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            = new DialogInterface.OnDismissListener() {
83db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        @Override
84db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        public void onDismiss(DialogInterface dialog) {
85db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            mDialog = null;
86db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        }
87db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    };
884c1bffecc94cedf56d188eca40bd65a854746413Sascha Haeberling    private final CountDownView mCountdownView;
890744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
9006db742814dd635d100639f977fcfdc904deb778Doris Liu    @Override
9106db742814dd635d100639f977fcfdc904deb778Doris Liu    public GestureDetector.OnGestureListener getGestureListener() {
9206db742814dd635d100639f977fcfdc904deb778Doris Liu        return mPreviewGestureListener;
9306db742814dd635d100639f977fcfdc904deb778Doris Liu    }
9406db742814dd635d100639f977fcfdc904deb778Doris Liu
954a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu    @Override
96d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    public View.OnTouchListener getTouchListener() {
97d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        return null;
98d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    }
99d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren
100d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    @Override
1014a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu    public void onPreviewLayoutChanged(View v, int left, int top, int right,
1024a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu            int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
1034a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu        int width = right - left;
1044a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu        int height = bottom - top;
1054a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu        if (mPreviewWidth != width || mPreviewHeight != height) {
1064a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu            mPreviewWidth = width;
1074a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu            mPreviewHeight = height;
108d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
1094a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu    }
110d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
11170da918464276b110c43868caa272c97baadb89eDoris Liu    @Override
11270da918464276b110c43868caa272c97baadb89eDoris Liu    public boolean shouldAutoAdjustTransformMatrixOnLayout() {
11370da918464276b110c43868caa272c97baadb89eDoris Liu        return true;
11470da918464276b110c43868caa272c97baadb89eDoris Liu    }
11570da918464276b110c43868caa272c97baadb89eDoris Liu
11670da918464276b110c43868caa272c97baadb89eDoris Liu    @Override
11711ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu    public void onPreviewFlipped() {
11811ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu        mController.updateCameraOrientation();
11911ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu    }
12011ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu
12108b0cddea8e7390bd21053d3049ea165c759d4dbDoris Liu    /**
1226c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu     * Starts the countdown timer.
1236c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu     *
1246c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu     * @param sec seconds to countdown
1256c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu     */
1266c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    public void startCountdown(int sec) {
1276c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu        mCountdownView.startCountDown(sec);
1286c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    }
1296c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu
1306c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    /**
1316c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu     * Sets a listener that gets notified when the countdown is finished.
1326c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu     */
1336c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    public void setCountdownFinishedListener(CountDownView.OnCountDownStatusListener listener) {
1346c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu        mCountdownView.setCountDownStatusListener(listener);
1356c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    }
1366c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu
1376c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    /**
1386c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu     * Returns whether the countdown is on-going.
1396c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu     */
1406c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    public boolean isCountingDown() {
1416c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu        return mCountdownView.isCountingDown();
1426c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    }
1436c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu
1446c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    /**
1456c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu     * Cancels the on-going countdown, if any.
1466c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu     */
1476c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    public void cancelCountDown() {
1486c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu        mCountdownView.cancelCountDown();
1496c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    }
1506c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu
1516c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    @Override
1526c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    public void onPreviewAreaChanged(RectF previewArea) {
1536c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu        if (mFaceView != null) {
1546c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu            mFaceView.onPreviewAreaChanged(previewArea);
1556c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu        }
1566c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu        mCountdownView.onPreviewAreaChanged(previewArea);
1576c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu    }
1586c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu
15936e56fba281292255a01ee00b4bee067fa09ab59Doris Liu    private class DecodeTask extends AsyncTask<Void, Void, Bitmap> {
16037f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling        private final byte [] mData;
161e2914fddcd6d4f78d812ef818d43364d9aa469d4Sascha Haeberling        private final int mOrientation;
162e2914fddcd6d4f78d812ef818d43364d9aa469d4Sascha Haeberling        private final boolean mMirror;
163c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu
16429da2db13029f8896018836693139a05d1139362Doris Liu        public DecodeTask(byte[] data, int orientation, boolean mirror) {
16537f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling            mData = data;
166ce2acbcb77225b6d429a23e00f69aadde8c2378bDoris Liu            mOrientation = orientation;
16729da2db13029f8896018836693139a05d1139362Doris Liu            mMirror = mirror;
168c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu        }
169c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu
170c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu        @Override
17136e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        protected Bitmap doInBackground(Void... params) {
17237f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling            // Decode image in background.
17300a764a3b6d9072413d18b441c759d4a604223b4Senpo Hu            return PictureDecoder.decode(mData, DOWN_SAMPLE_FACTOR, mOrientation, mMirror);
17437f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling        }
17537f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling    }
176c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu
17736e56fba281292255a01ee00b4bee067fa09ab59Doris Liu    private class DecodeImageForReview extends DecodeTask {
17836e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        public DecodeImageForReview(byte[] data, int orientation, boolean mirror) {
17936e56fba281292255a01ee00b4bee067fa09ab59Doris Liu            super(data, orientation, mirror);
18036e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        }
18136e56fba281292255a01ee00b4bee067fa09ab59Doris Liu
18236e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        @Override
18336e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        protected void onPostExecute(Bitmap bitmap) {
18436e56fba281292255a01ee00b4bee067fa09ab59Doris Liu            if (isCancelled()) {
18536e56fba281292255a01ee00b4bee067fa09ab59Doris Liu                return;
18636e56fba281292255a01ee00b4bee067fa09ab59Doris Liu            }
187b4a2222950f627a39267636fba19649974cb8734Spike Sprague
188b4a2222950f627a39267636fba19649974cb8734Spike Sprague            mIntentReviewImageView.setImageBitmap(bitmap);
189b4a2222950f627a39267636fba19649974cb8734Spike Sprague            showIntentReviewImageView();
190b4a2222950f627a39267636fba19649974cb8734Spike Sprague
19136e56fba281292255a01ee00b4bee067fa09ab59Doris Liu            mDecodeTaskForReview = null;
19236e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        }
19336e56fba281292255a01ee00b4bee067fa09ab59Doris Liu    }
19436e56fba281292255a01ee00b4bee067fa09ab59Doris Liu
195d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public PhotoUI(CameraActivity activity, PhotoController controller, View parent) {
196d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        mActivity = activity;
197d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        mController = controller;
198d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        mRootView = parent;
199d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
200f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        ViewGroup moduleRoot = (ViewGroup) mRootView.findViewById(R.id.module_layout);
201d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        mActivity.getLayoutInflater().inflate(R.layout.photo_module,
202e2914fddcd6d4f78d812ef818d43364d9aa469d4Sascha Haeberling                 moduleRoot, true);
203d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        initIndicators();
204987ee64612e2510004fdf08536746c87234d01c1Paul Rohde        mFocusRing = (FocusRing) mRootView.findViewById(R.id.focus_ring);
205f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu        mPreviewOverlay = (PreviewOverlay) mRootView.findViewById(R.id.preview_overlay);
2066c75164c89f3bbd4f894b9c49a7914a24268a999Doris Liu        mCountdownView = (CountDownView) mRootView.findViewById(R.id.count_down_view);
20762b4c3c0da3abd397b3790820359927784c50bc2Andy Huibers        // Show faces if we are in debug mode.
20862b4c3c0da3abd397b3790820359927784c50bc2Andy Huibers        if (DebugPropertyHelper.showCaptureDebugUI()) {
20962b4c3c0da3abd397b3790820359927784c50bc2Andy Huibers            mFaceView = (FaceView) mRootView.findViewById(R.id.face_view);
21062b4c3c0da3abd397b3790820359927784c50bc2Andy Huibers        } else {
21162b4c3c0da3abd397b3790820359927784c50bc2Andy Huibers            mFaceView = null;
21262b4c3c0da3abd397b3790820359927784c50bc2Andy Huibers        }
213b4a2222950f627a39267636fba19649974cb8734Spike Sprague
214b4a2222950f627a39267636fba19649974cb8734Spike Sprague        if (mController.isImageCaptureIntent()) {
21502b9b9af097ac7886ec1d23392cd87c9fbcb186fSpike Sprague            initIntentReviewImageView();
216b4a2222950f627a39267636fba19649974cb8734Spike Sprague        }
217b4a2222950f627a39267636fba19649974cb8734Spike Sprague    }
218b4a2222950f627a39267636fba19649974cb8734Spike Sprague
21902b9b9af097ac7886ec1d23392cd87c9fbcb186fSpike Sprague    private void initIntentReviewImageView() {
22002b9b9af097ac7886ec1d23392cd87c9fbcb186fSpike Sprague        mIntentReviewImageView = (ImageView) mRootView.findViewById(R.id.intent_review_imageview);
221b4a2222950f627a39267636fba19649974cb8734Spike Sprague        mActivity.getCameraAppUI().addPreviewAreaChangedListener(
222b4a2222950f627a39267636fba19649974cb8734Spike Sprague                new PreviewStatusListener.PreviewAreaChangedListener() {
223b4a2222950f627a39267636fba19649974cb8734Spike Sprague                    @Override
224b4a2222950f627a39267636fba19649974cb8734Spike Sprague                    public void onPreviewAreaChanged(RectF previewArea) {
225b4a2222950f627a39267636fba19649974cb8734Spike Sprague                        FrameLayout.LayoutParams params =
226b4a2222950f627a39267636fba19649974cb8734Spike Sprague                            (FrameLayout.LayoutParams) mIntentReviewImageView.getLayoutParams();
227b4a2222950f627a39267636fba19649974cb8734Spike Sprague                        params.width = (int) previewArea.width();
228b4a2222950f627a39267636fba19649974cb8734Spike Sprague                        params.height = (int) previewArea.height();
229b4a2222950f627a39267636fba19649974cb8734Spike Sprague                        params.setMargins((int) previewArea.left, (int) previewArea.top, 0, 0);
230b4a2222950f627a39267636fba19649974cb8734Spike Sprague                        mIntentReviewImageView.setLayoutParams(params);
231b4a2222950f627a39267636fba19649974cb8734Spike Sprague                    }
232b4a2222950f627a39267636fba19649974cb8734Spike Sprague                });
233b4a2222950f627a39267636fba19649974cb8734Spike Sprague    }
234b4a2222950f627a39267636fba19649974cb8734Spike Sprague
235b4a2222950f627a39267636fba19649974cb8734Spike Sprague    /**
236b4a2222950f627a39267636fba19649974cb8734Spike Sprague     * Show the image review over the live preview for intent captures.
237b4a2222950f627a39267636fba19649974cb8734Spike Sprague     */
238b4a2222950f627a39267636fba19649974cb8734Spike Sprague    public void showIntentReviewImageView() {
239b4a2222950f627a39267636fba19649974cb8734Spike Sprague        if (mIntentReviewImageView != null) {
240b4a2222950f627a39267636fba19649974cb8734Spike Sprague            mIntentReviewImageView.setVisibility(View.VISIBLE);
241b4a2222950f627a39267636fba19649974cb8734Spike Sprague        }
2426432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    }
2436432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu
244b4a2222950f627a39267636fba19649974cb8734Spike Sprague    /**
245b4a2222950f627a39267636fba19649974cb8734Spike Sprague     * Hide the image review over the live preview for intent captures.
246b4a2222950f627a39267636fba19649974cb8734Spike Sprague     */
247b4a2222950f627a39267636fba19649974cb8734Spike Sprague    public void hideIntentReviewImageView() {
248b4a2222950f627a39267636fba19649974cb8734Spike Sprague        if (mIntentReviewImageView != null) {
249b4a2222950f627a39267636fba19649974cb8734Spike Sprague            mIntentReviewImageView.setVisibility(View.INVISIBLE);
250b4a2222950f627a39267636fba19649974cb8734Spike Sprague        }
251b4a2222950f627a39267636fba19649974cb8734Spike Sprague    }
252b4a2222950f627a39267636fba19649974cb8734Spike Sprague
253b4a2222950f627a39267636fba19649974cb8734Spike Sprague
254987ee64612e2510004fdf08536746c87234d01c1Paul Rohde    public FocusRing getFocusRing() {
255987ee64612e2510004fdf08536746c87234d01c1Paul Rohde        return mFocusRing;
256482de029dc20e0a577388a602985fb31c3200309Doris Liu    }
257482de029dc20e0a577388a602985fb31c3200309Doris Liu
258d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu    public void updatePreviewAspectRatio(float aspectRatio) {
259d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu        if (aspectRatio <= 0) {
260d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu            Log.e(TAG, "Invalid aspect ratio: " + aspectRatio);
261d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu            return;
262d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu        }
263d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu        if (aspectRatio < 1f) {
264d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu            aspectRatio = 1f / aspectRatio;
265d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu        }
266d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu
267d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu        if (mAspectRatio != aspectRatio) {
268d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu            mAspectRatio = aspectRatio;
269d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu            // Update transform matrix with the new aspect ratio.
27070da918464276b110c43868caa272c97baadb89eDoris Liu            mController.updatePreviewAspectRatio(mAspectRatio);
271d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu        }
272d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu    }
273d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu
274dcccc510652b835fdbd39310a07849af8203052aAngus Kong    @Override
2756432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
276d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        mController.onPreviewUIReady();
2776432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    }
278d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
279dcccc510652b835fdbd39310a07849af8203052aAngus Kong    @Override
2806432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
2816432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu        // Ignored, Camera does all the work for us
2826432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    }
2836432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu
284dcccc510652b835fdbd39310a07849af8203052aAngus Kong    @Override
2856432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
286d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        mController.onPreviewUIDestroyed();
287d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        return true;
2886432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    }
2896432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu
2907b265a6b2f55c6ae7afc30e63ba324c4084a5d8eztenghui    @Override
2916432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
292d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
293d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
294d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    private void initIndicators() {
2950744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        // TODO init toggle buttons on bottom bar here
296d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
297d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
2986607dae6c4d1ee5bbf572695c2042d4d9129a730Angus Kong    public void onCameraOpened(CameraCapabilities capabilities, CameraSettings settings) {
2996607dae6c4d1ee5bbf572695c2042d4d9129a730Angus Kong        initializeZoom(capabilities, settings);
300eb3134f6ecc42f7d98625ca2c0ddfb06c9f07c43Spike Sprague    }
301eb3134f6ecc42f7d98625ca2c0ddfb06c9f07c43Spike Sprague
3020a6a8d8e4e1c9796aac606379a42970cdffb8911Erin Dahlgren    public void animateCapture(final byte[] jpegData, int orientation, boolean mirror) {
3030a6a8d8e4e1c9796aac606379a42970cdffb8911Erin Dahlgren        // Decode jpeg byte array and then animate the jpeg
3040a6a8d8e4e1c9796aac606379a42970cdffb8911Erin Dahlgren        DecodeTask task = new DecodeTask(jpegData, orientation, mirror);
3050a6a8d8e4e1c9796aac606379a42970cdffb8911Erin Dahlgren        task.execute();
306eb3134f6ecc42f7d98625ca2c0ddfb06c9f07c43Spike Sprague    }
307d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
308d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    // called from onResume but only the first time
309ffbc43c3dd3c94a968a41431fb07645a13696c4aKevin Gabayan    public void initializeFirstTime() {
3100744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
311d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
312d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
313d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    // called from onResume every other time
3146607dae6c4d1ee5bbf572695c2042d4d9129a730Angus Kong    public void initializeSecondTime(CameraCapabilities capabilities, CameraSettings settings) {
3156607dae6c4d1ee5bbf572695c2042d4d9129a730Angus Kong        initializeZoom(capabilities, settings);
316d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        if (mController.isImageCaptureIntent()) {
317d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            hidePostCaptureAlert();
318d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
319d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
320d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
3216607dae6c4d1ee5bbf572695c2042d4d9129a730Angus Kong    public void initializeZoom(CameraCapabilities capabilities, CameraSettings settings) {
3226607dae6c4d1ee5bbf572695c2042d4d9129a730Angus Kong        if ((capabilities == null) || settings == null ||
3236607dae6c4d1ee5bbf572695c2042d4d9129a730Angus Kong                !capabilities.supports(CameraCapabilities.Feature.ZOOM)) {
3241d943647c5b632588c4858ded04770e846341f1bSascha Haeberling            return;
3251d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        }
3262192fbaaf598d4440a8d537a70095ea56bc9a5ebSol Boucher        mZoomMax = capabilities.getMaxZoomRatio();
327d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        // Currently we use immediate zoom for fast zooming to get better UX and
328d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        // there is no plan to take advantage of the smooth zoom.
329f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu        // TODO: Need to setup a path to AppUI to do this
3302192fbaaf598d4440a8d537a70095ea56bc9a5ebSol Boucher        mPreviewOverlay.setupZoom(mZoomMax, settings.getCurrentZoomRatio(),
3316607dae6c4d1ee5bbf572695c2042d4d9129a730Angus Kong                new ZoomChangeListener());
332d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
333d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
334c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu    public void animateFlash() {
3351dfe7828fd60741b9752553af3ee439c04e758a0Doris Liu        mController.startPreCaptureAnimation();
336c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu    }
337c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu
338d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public boolean onBackPressed() {
339d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        // In image capture mode, back button should:
340d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        // 1) if there is any popup, dismiss them, 2) otherwise, get out of
341d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        // image capture
342d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        if (mController.isImageCaptureIntent()) {
343c3679c0961521165499380c77344acc69072b2acDoris Liu            mController.onCaptureCancelled();
344d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            return true;
345d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        } else if (!mController.isCameraIdle()) {
346d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            // ignore backs while we're taking a picture
347d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            return true;
348d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        } else {
349c3679c0961521165499380c77344acc69072b2acDoris Liu            return false;
350d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
351d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
352d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
35336e56fba281292255a01ee00b4bee067fa09ab59Doris Liu    protected void showCapturedImageForReview(byte[] jpegData, int orientation, boolean mirror) {
35436e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        mDecodeTaskForReview = new DecodeImageForReview(jpegData, orientation, mirror);
35536e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        mDecodeTaskForReview.execute();
3564efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren
3574efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        mActivity.getCameraAppUI().transitionToIntentReviewLayout();
358d31cdfeb1035df8ba939e877031769f0df247aa6Doris Liu        pauseFaceDetection();
359d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
360d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
361d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    protected void hidePostCaptureAlert() {
36236e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        if (mDecodeTaskForReview != null) {
36336e56fba281292255a01ee00b4bee067fa09ab59Doris Liu            mDecodeTaskForReview.cancel(true);
36436e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        }
365d31cdfeb1035df8ba939e877031769f0df247aa6Doris Liu        resumeFaceDetection();
366d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
367d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
368d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void setDisplayOrientation(int orientation) {
369d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        if (mFaceView != null) {
370d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            mFaceView.setDisplayOrientation(orientation);
371d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
372d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
373d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
374f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu    private class ZoomChangeListener implements PreviewOverlay.OnZoomChangedListener {
375d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        @Override
3762192fbaaf598d4440a8d537a70095ea56bc9a5ebSol Boucher        public void onZoomValueChanged(float ratio) {
3772192fbaaf598d4440a8d537a70095ea56bc9a5ebSol Boucher            mController.onZoomChanged(ratio);
378d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
379d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
380d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        @Override
381d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        public void onZoomStart() {
382d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
383d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
384d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        @Override
385d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        public void onZoomEnd() {
386d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
387d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
388d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
3896432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    public void setSwipingEnabled(boolean enable) {
3906432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu        mActivity.setSwipingEnabled(enable);
391d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
392d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
393d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void onPause() {
3941d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        if (mFaceView != null) {
3951d943647c5b632588c4858ded04770e846341f1bSascha Haeberling            mFaceView.clear();
3961d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        }
397db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        if (mDialog != null) {
398db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            mDialog.dismiss();
399db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        }
4007351415ddfaf7f563a4a12c9204e6feb20fdf49dAlan Newberger        // recalculate aspect ratio when restarting.
4017351415ddfaf7f563a4a12c9204e6feb20fdf49dAlan Newberger        mAspectRatio = 0.0f;
402d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
403d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
404d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void clearFaces() {
4050744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        if (mFaceView != null) {
4060744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            mFaceView.clear();
4070744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        }
408d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
409d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
410d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void pauseFaceDetection() {
4111d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        if (mFaceView != null) {
4121d943647c5b632588c4858ded04770e846341f1bSascha Haeberling            mFaceView.pause();
4131d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        }
414d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
415d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
416d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void resumeFaceDetection() {
4171d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        if (mFaceView != null) {
4181d943647c5b632588c4858ded04770e846341f1bSascha Haeberling            mFaceView.resume();
4191d943647c5b632588c4858ded04770e846341f1bSascha Haeberling        }
420d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
421d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
422d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void onStartFaceDetection(int orientation, boolean mirror) {
423d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu        if (mFaceView != null) {
424d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu            mFaceView.clear();
425d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu            mFaceView.setVisibility(View.VISIBLE);
426d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu            mFaceView.setDisplayOrientation(orientation);
427d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu            mFaceView.setMirror(mirror);
428d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu            mFaceView.resume();
429d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu        }
430d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
431d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
432d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    @Override
4335a344964cb003525727c31d295ca3a592c245606Sol Boucher    public void onFaceDetection(Face[] faces, CameraAgent.CameraProxy camera) {
434d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu        if (mFaceView != null) {
435d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu            mFaceView.setFaces(faces);
436d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu        }
437d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
438d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
439d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb}
440