PhotoUI.java revision db8f97582d09cd36eee8cfe4ed43182bff63f8bd
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;
236432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liuimport android.graphics.SurfaceTexture;
24d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport android.hardware.Camera;
25d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport android.hardware.Camera.Face;
2637f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberlingimport android.os.AsyncTask;
27f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liuimport android.view.GestureDetector;
28f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liuimport android.view.MotionEvent;
29d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport android.view.View;
30d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport android.view.ViewGroup;
31d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
32d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport com.android.camera.FocusOverlayManager.FocusUI;
331045fefdf22bd58fa911b100e7db5750f7efa3e6Angus Kongimport com.android.camera.cameradevice.CameraManager;
345596b4c902dcb685928b43678f428746ca5ffd08Angus Kongimport com.android.camera.debug.Log;
35d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport com.android.camera.ui.FaceView;
36f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liuimport com.android.camera.ui.PreviewOverlay;
3706db742814dd635d100639f977fcfdc904deb778Doris Liuimport com.android.camera.ui.PreviewStatusListener;
38b50b5cbfbc0a67db6fc43373363b10381c9c61a3Angus Kongimport com.android.camera.util.CameraUtil;
39db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liuimport com.android.camera.widget.AspectRatioDialogLayout;
40db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liuimport com.android.camera.widget.AspectRatioSelector;
41db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liuimport com.android.camera.widget.LocationDialogLayout;
428e963a5a6016d246184ed65906f9d103e92b17e2Sascha Haeberlingimport com.android.camera2.R;
43b50b5cbfbc0a67db6fc43373363b10381c9c61a3Angus Kong
44b50b5cbfbc0a67db6fc43373363b10381c9c61a3Angus Kongimport java.util.List;
45d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
46482de029dc20e0a577388a602985fb31c3200309Doris Liupublic class PhotoUI implements PreviewStatusListener,
479e76552adff6ecf8b8e4070ecd61699cb6d18269Angus Kong    CameraManager.CameraFaceDetectionCallback {
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;
54482de029dc20e0a577388a602985fb31c3200309Doris Liu    private final FocusUI mFocusUI;
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.
62d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu    private FaceView mFaceView = null;
6336e56fba281292255a01ee00b4bee067fa09ab59Doris Liu    private DecodeImageForReview mDecodeTaskForReview = null;
64d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
65d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    private int mZoomMax;
66d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    private List<Integer> mZoomRatios;
67d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
68d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    private int mPreviewWidth = 0;
69d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    private int mPreviewHeight = 0;
7070da918464276b110c43868caa272c97baadb89eDoris Liu    private float mAspectRatio = UNSET;
710744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
7206db742814dd635d100639f977fcfdc904deb778Doris Liu    private final GestureDetector.OnGestureListener mPreviewGestureListener
7306db742814dd635d100639f977fcfdc904deb778Doris Liu            = new GestureDetector.SimpleOnGestureListener() {
7406db742814dd635d100639f977fcfdc904deb778Doris Liu        @Override
7506db742814dd635d100639f977fcfdc904deb778Doris Liu        public boolean onSingleTapUp(MotionEvent ev) {
7606db742814dd635d100639f977fcfdc904deb778Doris Liu            mController.onSingleTapUp(null, (int) ev.getX(), (int) ev.getY());
7706db742814dd635d100639f977fcfdc904deb778Doris Liu            return true;
7806db742814dd635d100639f977fcfdc904deb778Doris Liu        }
7906db742814dd635d100639f977fcfdc904deb778Doris Liu    };
80db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    private final DialogInterface.OnDismissListener mOnDismissListener
81db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            = new DialogInterface.OnDismissListener() {
82db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        @Override
83db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        public void onDismiss(DialogInterface dialog) {
84db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            mDialog = null;
85db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        }
86db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    };
870744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
8806db742814dd635d100639f977fcfdc904deb778Doris Liu    @Override
8906db742814dd635d100639f977fcfdc904deb778Doris Liu    public GestureDetector.OnGestureListener getGestureListener() {
9006db742814dd635d100639f977fcfdc904deb778Doris Liu        return mPreviewGestureListener;
9106db742814dd635d100639f977fcfdc904deb778Doris Liu    }
9206db742814dd635d100639f977fcfdc904deb778Doris Liu
934a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu    @Override
94d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    public View.OnTouchListener getTouchListener() {
95d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        return null;
96d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    }
97d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren
98d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren    @Override
994a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu    public void onPreviewLayoutChanged(View v, int left, int top, int right,
1004a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu            int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
1014a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu        int width = right - left;
1024a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu        int height = bottom - top;
1034a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu        if (mPreviewWidth != width || mPreviewHeight != height) {
1044a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu            mPreviewWidth = width;
1054a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu            mPreviewHeight = height;
106d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
1074a010db8a60008b2bf67b93b64f77f63affc29f3Doris Liu    }
108d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
10970da918464276b110c43868caa272c97baadb89eDoris Liu    @Override
11070da918464276b110c43868caa272c97baadb89eDoris Liu    public boolean shouldAutoAdjustTransformMatrixOnLayout() {
11170da918464276b110c43868caa272c97baadb89eDoris Liu        return true;
11270da918464276b110c43868caa272c97baadb89eDoris Liu    }
11370da918464276b110c43868caa272c97baadb89eDoris Liu
11470da918464276b110c43868caa272c97baadb89eDoris Liu    @Override
11570da918464276b110c43868caa272c97baadb89eDoris Liu    public boolean shouldAutoAdjustBottomBar() {
11670da918464276b110c43868caa272c97baadb89eDoris Liu        return true;
11770da918464276b110c43868caa272c97baadb89eDoris Liu    }
11870da918464276b110c43868caa272c97baadb89eDoris Liu
11911ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu    @Override
12011ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu    public void onPreviewFlipped() {
12111ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu        mController.updateCameraOrientation();
12211ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu    }
12311ddd7389b89e9a876eba607e246e8b8d0dfecdfDoris Liu
12436e56fba281292255a01ee00b4bee067fa09ab59Doris Liu    private class DecodeTask extends AsyncTask<Void, Void, Bitmap> {
12537f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling        private final byte [] mData;
126e2914fddcd6d4f78d812ef818d43364d9aa469d4Sascha Haeberling        private final int mOrientation;
127e2914fddcd6d4f78d812ef818d43364d9aa469d4Sascha Haeberling        private final boolean mMirror;
128c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu
12929da2db13029f8896018836693139a05d1139362Doris Liu        public DecodeTask(byte[] data, int orientation, boolean mirror) {
13037f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling            mData = data;
131ce2acbcb77225b6d429a23e00f69aadde8c2378bDoris Liu            mOrientation = orientation;
13229da2db13029f8896018836693139a05d1139362Doris Liu            mMirror = mirror;
133c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu        }
134c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu
135c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu        @Override
13636e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        protected Bitmap doInBackground(Void... params) {
13737f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling            // Decode image in background.
138ce2acbcb77225b6d429a23e00f69aadde8c2378bDoris Liu            Bitmap bitmap = CameraUtil.downSample(mData, DOWN_SAMPLE_FACTOR);
13929da2db13029f8896018836693139a05d1139362Doris Liu            if (mOrientation != 0 || mMirror) {
140ce2acbcb77225b6d429a23e00f69aadde8c2378bDoris Liu                Matrix m = new Matrix();
14129da2db13029f8896018836693139a05d1139362Doris Liu                if (mMirror) {
14229da2db13029f8896018836693139a05d1139362Doris Liu                    // Flip horizontally
14329da2db13029f8896018836693139a05d1139362Doris Liu                    m.setScale(-1f, 1f);
14429da2db13029f8896018836693139a05d1139362Doris Liu                }
145cec75e408a2d451b90bac5f06e10906ffcafff33Andy Huibers                m.preRotate(mOrientation);
146ce2acbcb77225b6d429a23e00f69aadde8c2378bDoris Liu                return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m,
147ce2acbcb77225b6d429a23e00f69aadde8c2378bDoris Liu                        false);
148ce2acbcb77225b6d429a23e00f69aadde8c2378bDoris Liu            }
149ce2acbcb77225b6d429a23e00f69aadde8c2378bDoris Liu            return bitmap;
15037f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling        }
15137f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling    }
152c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu
15336e56fba281292255a01ee00b4bee067fa09ab59Doris Liu    private class DecodeImageForReview extends DecodeTask {
15436e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        public DecodeImageForReview(byte[] data, int orientation, boolean mirror) {
15536e56fba281292255a01ee00b4bee067fa09ab59Doris Liu            super(data, orientation, mirror);
15636e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        }
15736e56fba281292255a01ee00b4bee067fa09ab59Doris Liu
15836e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        @Override
15936e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        protected void onPostExecute(Bitmap bitmap) {
16036e56fba281292255a01ee00b4bee067fa09ab59Doris Liu            if (isCancelled()) {
16136e56fba281292255a01ee00b4bee067fa09ab59Doris Liu                return;
16236e56fba281292255a01ee00b4bee067fa09ab59Doris Liu            }
16336e56fba281292255a01ee00b4bee067fa09ab59Doris Liu            mDecodeTaskForReview = null;
16436e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        }
16536e56fba281292255a01ee00b4bee067fa09ab59Doris Liu    }
16636e56fba281292255a01ee00b4bee067fa09ab59Doris Liu
167d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public PhotoUI(CameraActivity activity, PhotoController controller, View parent) {
168d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        mActivity = activity;
169d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        mController = controller;
170d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        mRootView = parent;
171d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
172f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        ViewGroup moduleRoot = (ViewGroup) mRootView.findViewById(R.id.module_layout);
173d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        mActivity.getLayoutInflater().inflate(R.layout.photo_module,
174e2914fddcd6d4f78d812ef818d43364d9aa469d4Sascha Haeberling                 moduleRoot, true);
175d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        initIndicators();
176482de029dc20e0a577388a602985fb31c3200309Doris Liu        mFocusUI = (FocusUI) mRootView.findViewById(R.id.focus_overlay);
177f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu        mPreviewOverlay = (PreviewOverlay) mRootView.findViewById(R.id.preview_overlay);
1786432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    }
1796432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu
180482de029dc20e0a577388a602985fb31c3200309Doris Liu    public FocusUI getFocusUI() {
181482de029dc20e0a577388a602985fb31c3200309Doris Liu        return mFocusUI;
182482de029dc20e0a577388a602985fb31c3200309Doris Liu    }
183482de029dc20e0a577388a602985fb31c3200309Doris Liu
184d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu    public void updatePreviewAspectRatio(float aspectRatio) {
185d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu        if (aspectRatio <= 0) {
186d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu            Log.e(TAG, "Invalid aspect ratio: " + aspectRatio);
187d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu            return;
188d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu        }
189d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu        if (aspectRatio < 1f) {
190d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu            aspectRatio = 1f / aspectRatio;
191d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu        }
192d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu
193d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu        if (mAspectRatio != aspectRatio) {
194d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu            mAspectRatio = aspectRatio;
195d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu            // Update transform matrix with the new aspect ratio.
19670da918464276b110c43868caa272c97baadb89eDoris Liu            mController.updatePreviewAspectRatio(mAspectRatio);
197d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu        }
198d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu    }
199d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu
200dcccc510652b835fdbd39310a07849af8203052aAngus Kong    @Override
2016432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
202d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        mController.onPreviewUIReady();
2036432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    }
204d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
205dcccc510652b835fdbd39310a07849af8203052aAngus Kong    @Override
2066432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
2076432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu        // Ignored, Camera does all the work for us
2086432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    }
2096432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu
210dcccc510652b835fdbd39310a07849af8203052aAngus Kong    @Override
2116432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
212d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        mController.onPreviewUIDestroyed();
213d8de077f72b04cee1bdf26e5ca1678ac5297bd71Erin Dahlgren        return true;
2146432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    }
2156432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu
2167b265a6b2f55c6ae7afc30e63ba324c4084a5d8eztenghui    @Override
2176432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
218d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
219d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
220d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public View getRootView() {
221d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        return mRootView;
222d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
223d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
224d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    private void initIndicators() {
2250744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        // TODO init toggle buttons on bottom bar here
226d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
227d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
228b1641f5df0cf839b54385ea4d2e43521620fc237Erin Dahlgren    public void onCameraOpened(Camera.Parameters params) {
229eb3134f6ecc42f7d98625ca2c0ddfb06c9f07c43Spike Sprague        initializeZoom(params);
230eb3134f6ecc42f7d98625ca2c0ddfb06c9f07c43Spike Sprague    }
231eb3134f6ecc42f7d98625ca2c0ddfb06c9f07c43Spike Sprague
2320a6a8d8e4e1c9796aac606379a42970cdffb8911Erin Dahlgren    public void animateCapture(final byte[] jpegData, int orientation, boolean mirror) {
2330a6a8d8e4e1c9796aac606379a42970cdffb8911Erin Dahlgren        // Decode jpeg byte array and then animate the jpeg
2340a6a8d8e4e1c9796aac606379a42970cdffb8911Erin Dahlgren        DecodeTask task = new DecodeTask(jpegData, orientation, mirror);
2350a6a8d8e4e1c9796aac606379a42970cdffb8911Erin Dahlgren        task.execute();
236eb3134f6ecc42f7d98625ca2c0ddfb06c9f07c43Spike Sprague    }
237d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
238d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    // called from onResume but only the first time
239ffbc43c3dd3c94a968a41431fb07645a13696c4aKevin Gabayan    public void initializeFirstTime() {
2400744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
241d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
242d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
243d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    // called from onResume every other time
244d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void initializeSecondTime(Camera.Parameters params) {
245d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        initializeZoom(params);
246d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        if (mController.isImageCaptureIntent()) {
247d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            hidePostCaptureAlert();
248d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
249357b7673f03d9b45d281d585cc3f4f87dc7d727bErin Dahlgren        // Removes pie menu.
250d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
251d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
252db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    public void showLocationAndAspectRatioDialog(
253db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            final PhotoModule.LocationDialogCallback locationCallback,
254db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            final PhotoModule.AspectRatioDialogCallback aspectRatioDialogCallback) {
255db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        setDialog(new Dialog(mActivity,
256db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                android.R.style.Theme_Black_NoTitleBar_Fullscreen));
257db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        final LocationDialogLayout locationDialogLayout = (LocationDialogLayout) mActivity
258db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                .getLayoutInflater().inflate(R.layout.location_dialog_layout, null);
259db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        locationDialogLayout.setLocationTaggingSelectionListener(
260db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                new LocationDialogLayout.LocationTaggingSelectionListener() {
261db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            @Override
262db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            public void onLocationTaggingSelected(boolean selected) {
263db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                // Update setting.
264db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                locationCallback.onLocationTaggingSelected(selected);
265db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                // Go to next page.
266db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                showAspectRatioDialog(aspectRatioDialogCallback, mDialog);
267db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            }
268db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        });
269db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        mDialog.setContentView(locationDialogLayout, new ViewGroup.LayoutParams(
270db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
271db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        mDialog.show();
272db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    }
273db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu
274db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    /**
275db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu     * Dismisses previous dialog if any, sets current dialog to the given dialog,
276db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu     * and set the on dismiss listener for the given dialog.
277db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu     * @param dialog dialog to show
278db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu     */
279db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    private void setDialog(Dialog dialog) {
280db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        if (mDialog != null) {
281db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            mDialog.setOnDismissListener(null);
282db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            mDialog.dismiss();
283db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        }
284db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        mDialog = dialog;
285db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        if (mDialog != null) {
286db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            mDialog.setOnDismissListener(mOnDismissListener);
287db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        }
288db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    }
289db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu
290db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    public void showAspectRatioDialog(final PhotoModule.AspectRatioDialogCallback callback) {
291db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        setDialog(new Dialog(mActivity, android.R.style.Theme_Black_NoTitleBar_Fullscreen));
292db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        showAspectRatioDialog(callback, mDialog);
293db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    }
294db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu
295db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu    private void showAspectRatioDialog(final PhotoModule.AspectRatioDialogCallback callback,
296db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            final Dialog aspectRatioDialog) {
297db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        if (aspectRatioDialog == null) {
298db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            Log.e(TAG, "Dialog for aspect ratio is null.");
299db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            return;
300db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        }
301db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        final AspectRatioDialogLayout aspectRatioDialogLayout =
302db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                (AspectRatioDialogLayout) mActivity
303db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                .getLayoutInflater().inflate(R.layout.aspect_ratio_dialog_layout, null);
304db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        aspectRatioDialogLayout.initialize(
305db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                new AspectRatioDialogLayout.AspectRatioChangedListener() {
306db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                    @Override
307db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                    public void onAspectRatioChanged(AspectRatioSelector.AspectRatio aspectRatio) {
308db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                        aspectRatioDialog.dismiss();
309db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                        // callback to set picture size.
310db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                        callback.onAspectRatioSelected(aspectRatio);
311db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                    }
312db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                }, callback.get4x3AspectRatioText(), callback.get16x9AspectRatioText(),
313db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                callback.getCurrentAspectRatio());
314db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        aspectRatioDialog.setContentView(aspectRatioDialogLayout, new ViewGroup.LayoutParams(
315db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
316db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        aspectRatioDialog.show();
3176a83d528b09c55ade6ad44b82c81d4476ac57441Doris Liu    }
3186a83d528b09c55ade6ad44b82c81d4476ac57441Doris Liu
319d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void initializeZoom(Camera.Parameters params) {
320f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu        if ((params == null) || !params.isZoomSupported()) return;
321d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        mZoomMax = params.getMaxZoom();
322d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        mZoomRatios = params.getZoomRatios();
323d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        // Currently we use immediate zoom for fast zooming to get better UX and
324d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        // there is no plan to take advantage of the smooth zoom.
325f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu        // TODO: Need to setup a path to AppUI to do this
326f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu        mPreviewOverlay.setupZoom(mZoomMax, params.getZoom(), mZoomRatios, new ZoomChangeListener());
327d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
328d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
329c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu    public void animateFlash() {
3301dfe7828fd60741b9752553af3ee439c04e758a0Doris Liu        mController.startPreCaptureAnimation();
331c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu    }
332c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu
333d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public boolean onBackPressed() {
334d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        // In image capture mode, back button should:
335d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        // 1) if there is any popup, dismiss them, 2) otherwise, get out of
336d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        // image capture
337d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        if (mController.isImageCaptureIntent()) {
338c3679c0961521165499380c77344acc69072b2acDoris Liu            mController.onCaptureCancelled();
339d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            return true;
340d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        } else if (!mController.isCameraIdle()) {
341d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            // ignore backs while we're taking a picture
342d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            return true;
343d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        } else {
344c3679c0961521165499380c77344acc69072b2acDoris Liu            return false;
345d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
346d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
347d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
34836e56fba281292255a01ee00b4bee067fa09ab59Doris Liu    protected void showCapturedImageForReview(byte[] jpegData, int orientation, boolean mirror) {
34936e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        mDecodeTaskForReview = new DecodeImageForReview(jpegData, orientation, mirror);
35036e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        mDecodeTaskForReview.execute();
3514efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren
3524efa8b54c1df4e06f2d3caed2568015a737f9ddaErin Dahlgren        mActivity.getCameraAppUI().transitionToIntentReviewLayout();
353d31cdfeb1035df8ba939e877031769f0df247aa6Doris Liu        pauseFaceDetection();
354d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
355d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
356d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    protected void hidePostCaptureAlert() {
35736e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        if (mDecodeTaskForReview != null) {
35836e56fba281292255a01ee00b4bee067fa09ab59Doris Liu            mDecodeTaskForReview.cancel(true);
35936e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        }
360d31cdfeb1035df8ba939e877031769f0df247aa6Doris Liu        resumeFaceDetection();
361d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
362d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
363d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void setDisplayOrientation(int orientation) {
364d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        if (mFaceView != null) {
365d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            mFaceView.setDisplayOrientation(orientation);
366d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
367d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
368d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
369f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu    private class ZoomChangeListener implements PreviewOverlay.OnZoomChangedListener {
370d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        @Override
371d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        public void onZoomValueChanged(int index) {
372f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu            mController.onZoomChanged(index);
373d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
374d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
375d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        @Override
376d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        public void onZoomStart() {
377d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
378d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
379d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        @Override
380d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        public void onZoomEnd() {
381d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
382d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
383d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
3846432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    public void setSwipingEnabled(boolean enable) {
3856432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu        mActivity.setSwipingEnabled(enable);
386d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
387d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
388d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void onPause() {
389d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        if (mFaceView != null) mFaceView.clear();
390db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        if (mDialog != null) {
391db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu            mDialog.dismiss();
392db8f97582d09cd36eee8cfe4ed43182bff63f8bdDoris Liu        }
393d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
394d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
395d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void clearFaces() {
3960744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        if (mFaceView != null) {
3970744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            mFaceView.clear();
3980744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        }
399d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
400d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
401d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void pauseFaceDetection() {
402d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        if (mFaceView != null) mFaceView.pause();
403d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
404d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
405d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void resumeFaceDetection() {
406d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        if (mFaceView != null) mFaceView.resume();
407d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
408d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
409d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void onStartFaceDetection(int orientation, boolean mirror) {
410d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu        if (mFaceView != null) {
411d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu            mFaceView.clear();
412d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu            mFaceView.setVisibility(View.VISIBLE);
413d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu            mFaceView.setDisplayOrientation(orientation);
414d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu            mFaceView.setMirror(mirror);
415d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu            mFaceView.resume();
416d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu        }
417d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
418d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
419d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    @Override
4209e76552adff6ecf8b8e4070ecd61699cb6d18269Angus Kong    public void onFaceDetection(Face[] faces, CameraManager.CameraProxy camera) {
421d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu        if (mFaceView != null) {
422d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu            mFaceView.setFaces(faces);
423d27ea7be496ae823fa88b98760c1a9d9ce0d554dDoris Liu        }
424d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
425d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
42659401045bf479b2617c981075aec92190ec59aebDoris Liu    /**
4272bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong     * Returns a {@link com.android.camera.ui.PreviewStatusListener.PreviewAreaChangedListener}
42859401045bf479b2617c981075aec92190ec59aebDoris Liu     * that should be registered to listen to preview area change.
42959401045bf479b2617c981075aec92190ec59aebDoris Liu     */
4302bacca795a1b0adb0daf515c43c48234b44bbba5Angus Kong    public PreviewAreaChangedListener getPreviewAreaSizeChangedListener() {
43159401045bf479b2617c981075aec92190ec59aebDoris Liu        return mFaceView;
43259401045bf479b2617c981075aec92190ec59aebDoris Liu    }
43359401045bf479b2617c981075aec92190ec59aebDoris Liu
434d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb}
435