PhotoUI.java revision 0f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57ea
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
196a83d528b09c55ade6ad44b82c81d4476ac57441Doris Liuimport android.app.AlertDialog;
2037f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberlingimport android.graphics.Bitmap;
216432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liuimport android.graphics.Matrix;
2236ebcb11b15fb00d3a641499c0f8a16745a2fbb0Doris Liuimport android.graphics.RectF;
236432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liuimport android.graphics.SurfaceTexture;
24d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport android.hardware.Camera;
25d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport android.hardware.Camera.Face;
2637f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberlingimport android.os.AsyncTask;
27d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport android.util.Log;
28f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liuimport android.view.GestureDetector;
29f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liuimport android.view.MotionEvent;
306432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liuimport android.view.TextureView;
31d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport android.view.View;
32d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport android.view.View.OnClickListener;
33d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport android.view.View.OnLayoutChangeListener;
34d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport android.view.ViewGroup;
35d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport android.view.ViewStub;
36d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport android.widget.FrameLayout.LayoutParams;
3737f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberlingimport android.widget.ImageView;
38d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport android.widget.Toast;
390744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissenimport android.widget.ToggleButton;
400744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissenimport android.widget.CompoundButton;
41d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
42d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport com.android.camera.FocusOverlayManager.FocusUI;
4320fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kongimport com.android.camera.app.CameraManager;
448a2933b2c0156b752425b499f3081e4ffc350061Erin Dahlgrenimport com.android.camera.settings.SettingsManager;
450f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Spragueimport com.android.camera.ui.BottomBar;
46d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport com.android.camera.ui.FaceView;
47d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolbimport com.android.camera.ui.FocusIndicator;
48f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liuimport com.android.camera.ui.PreviewOverlay;
4906db742814dd635d100639f977fcfdc904deb778Doris Liuimport com.android.camera.ui.PreviewStatusListener;
50b50b5cbfbc0a67db6fc43373363b10381c9c61a3Angus Kongimport com.android.camera.util.CameraUtil;
518e963a5a6016d246184ed65906f9d103e92b17e2Sascha Haeberlingimport com.android.camera2.R;
52b50b5cbfbc0a67db6fc43373363b10381c9c61a3Angus Kong
53b50b5cbfbc0a67db6fc43373363b10381c9c61a3Angus Kongimport java.util.List;
54d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
55f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liupublic class PhotoUI implements
5606db742814dd635d100639f977fcfdc904deb778Doris Liu    FocusUI, PreviewStatusListener,
579e76552adff6ecf8b8e4070ecd61699cb6d18269Angus Kong    CameraManager.CameraFaceDetectionCallback {
58d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
590744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    private static final String TAG = "PhotoUI";
6037f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling    private static final int DOWN_SAMPLE_FACTOR = 4;
610f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague
62f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu    private final PreviewOverlay mPreviewOverlay;
63d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    private CameraActivity mActivity;
64d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    private PhotoController mController;
65d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
66d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    private View mRootView;
67dcccc510652b835fdbd39310a07849af8203052aAngus Kong    private SurfaceTexture mSurfaceTexture;
68d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
69d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    private FaceView mFaceView;
70d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    private View mReviewCancelButton;
71d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    private View mReviewDoneButton;
72d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    private View mReviewRetakeButton;
7336e56fba281292255a01ee00b4bee067fa09ab59Doris Liu    private ImageView mReviewImage;
7436e56fba281292255a01ee00b4bee067fa09ab59Doris Liu    private DecodeImageForReview mDecodeTaskForReview = null;
75d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    private Toast mNotSelectableToast;
76d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
77d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    private int mZoomMax;
78d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    private List<Integer> mZoomRatios;
79d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
80d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    private int mPreviewWidth = 0;
81d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    private int mPreviewHeight = 0;
826432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    private float mSurfaceTextureUncroppedWidth;
836432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    private float mSurfaceTextureUncroppedHeight;
846432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu
85c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu    private View mFlashOverlay;
86d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
876432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    private SurfaceTextureSizeChangedListener mSurfaceTextureSizeListener;
886432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    private TextureView mTextureView;
896432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    private Matrix mMatrix = null;
906432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    private float mAspectRatio = 4f / 3f;
91b09b53efcd179d55836014dcd054cff6f7d688d8Erin Dahlgren    private final Object mSurfaceTextureLock = new Object();
920f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague    private BottomBar mBottomBar;
930f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague    private final int mBottomBarMinHeight;
940f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague    private final int mBottomBarOptimalHeight;
950744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
960744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    private boolean mHideFocusRing;
970744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    private boolean mImmediateCapture;
980f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague
9906db742814dd635d100639f977fcfdc904deb778Doris Liu    private final GestureDetector.OnGestureListener mPreviewGestureListener
10006db742814dd635d100639f977fcfdc904deb778Doris Liu            = new GestureDetector.SimpleOnGestureListener() {
10106db742814dd635d100639f977fcfdc904deb778Doris Liu        @Override
10206db742814dd635d100639f977fcfdc904deb778Doris Liu        public boolean onSingleTapUp(MotionEvent ev) {
10306db742814dd635d100639f977fcfdc904deb778Doris Liu            mController.onSingleTapUp(null, (int) ev.getX(), (int) ev.getY());
10406db742814dd635d100639f977fcfdc904deb778Doris Liu            return true;
10506db742814dd635d100639f977fcfdc904deb778Doris Liu        }
10606db742814dd635d100639f977fcfdc904deb778Doris Liu    };
1070744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
1080744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    /*
1090744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen     * @return Whether immediate capture mode is selected from the toggle button
1100744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen     */
1110744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    // TODO: don't ship with this
1120744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    public boolean isImmediateCapture() {
1130744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        return mImmediateCapture;
1140744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen    }
1156432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu
11606db742814dd635d100639f977fcfdc904deb778Doris Liu    @Override
11706db742814dd635d100639f977fcfdc904deb778Doris Liu    public GestureDetector.OnGestureListener getGestureListener() {
11806db742814dd635d100639f977fcfdc904deb778Doris Liu        return mPreviewGestureListener;
11906db742814dd635d100639f977fcfdc904deb778Doris Liu    }
12006db742814dd635d100639f977fcfdc904deb778Doris Liu
1216432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    public interface SurfaceTextureSizeChangedListener {
1226432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu        public void onSurfaceTextureSizeChanged(int uncroppedWidth, int uncroppedHeight);
1236432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    }
1246432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu
125d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    private OnLayoutChangeListener mLayoutListener = new OnLayoutChangeListener() {
126d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        @Override
127d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        public void onLayoutChange(View v, int left, int top, int right,
128d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb                int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
129d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            int width = right - left;
130d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            int height = bottom - top;
1316432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu            if (mPreviewWidth != width || mPreviewHeight != height) {
1326432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu                mPreviewWidth = width;
1336432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu                mPreviewHeight = height;
13413ca71ebdbb2eb9c492da16262311b1290474f7dDoris Liu                setTransformMatrix(width, height);
135d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            }
136d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
137d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    };
138d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
13936e56fba281292255a01ee00b4bee067fa09ab59Doris Liu    private class DecodeTask extends AsyncTask<Void, Void, Bitmap> {
14037f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling        private final byte [] mData;
141ce2acbcb77225b6d429a23e00f69aadde8c2378bDoris Liu        private int mOrientation;
14229da2db13029f8896018836693139a05d1139362Doris Liu        private boolean mMirror;
143c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu
14429da2db13029f8896018836693139a05d1139362Doris Liu        public DecodeTask(byte[] data, int orientation, boolean mirror) {
14537f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling            mData = data;
146ce2acbcb77225b6d429a23e00f69aadde8c2378bDoris Liu            mOrientation = orientation;
14729da2db13029f8896018836693139a05d1139362Doris Liu            mMirror = mirror;
148c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu        }
149c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu
150c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu        @Override
15136e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        protected Bitmap doInBackground(Void... params) {
15237f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling            // Decode image in background.
153ce2acbcb77225b6d429a23e00f69aadde8c2378bDoris Liu            Bitmap bitmap = CameraUtil.downSample(mData, DOWN_SAMPLE_FACTOR);
15429da2db13029f8896018836693139a05d1139362Doris Liu            if (mOrientation != 0 || mMirror) {
155ce2acbcb77225b6d429a23e00f69aadde8c2378bDoris Liu                Matrix m = new Matrix();
15629da2db13029f8896018836693139a05d1139362Doris Liu                if (mMirror) {
15729da2db13029f8896018836693139a05d1139362Doris Liu                    // Flip horizontally
15829da2db13029f8896018836693139a05d1139362Doris Liu                    m.setScale(-1f, 1f);
15929da2db13029f8896018836693139a05d1139362Doris Liu                }
160cec75e408a2d451b90bac5f06e10906ffcafff33Andy Huibers                m.preRotate(mOrientation);
161ce2acbcb77225b6d429a23e00f69aadde8c2378bDoris Liu                return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), m,
162ce2acbcb77225b6d429a23e00f69aadde8c2378bDoris Liu                        false);
163ce2acbcb77225b6d429a23e00f69aadde8c2378bDoris Liu            }
164ce2acbcb77225b6d429a23e00f69aadde8c2378bDoris Liu            return bitmap;
16537f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling        }
16637f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling    }
167c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu
16836e56fba281292255a01ee00b4bee067fa09ab59Doris Liu    private class DecodeImageForReview extends DecodeTask {
16936e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        public DecodeImageForReview(byte[] data, int orientation, boolean mirror) {
17036e56fba281292255a01ee00b4bee067fa09ab59Doris Liu            super(data, orientation, mirror);
17136e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        }
17236e56fba281292255a01ee00b4bee067fa09ab59Doris Liu
17336e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        @Override
17436e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        protected void onPostExecute(Bitmap bitmap) {
17536e56fba281292255a01ee00b4bee067fa09ab59Doris Liu            if (isCancelled()) {
17636e56fba281292255a01ee00b4bee067fa09ab59Doris Liu                return;
17736e56fba281292255a01ee00b4bee067fa09ab59Doris Liu            }
17836e56fba281292255a01ee00b4bee067fa09ab59Doris Liu            mReviewImage.setImageBitmap(bitmap);
17936e56fba281292255a01ee00b4bee067fa09ab59Doris Liu            mReviewImage.setVisibility(View.VISIBLE);
18036e56fba281292255a01ee00b4bee067fa09ab59Doris Liu            mDecodeTaskForReview = null;
18136e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        }
18236e56fba281292255a01ee00b4bee067fa09ab59Doris Liu    }
18336e56fba281292255a01ee00b4bee067fa09ab59Doris Liu
184d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public PhotoUI(CameraActivity activity, PhotoController controller, View parent) {
185d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        mActivity = activity;
186d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        mController = controller;
187d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        mRootView = parent;
188d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
189f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        ViewGroup moduleRoot = (ViewGroup) mRootView.findViewById(R.id.module_layout);
190d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        mActivity.getLayoutInflater().inflate(R.layout.photo_module,
191f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu                 (ViewGroup) moduleRoot, true);
1920744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
193c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu        mFlashOverlay = mRootView.findViewById(R.id.flash_overlay);
1946432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu        // display the view
1956432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu        mTextureView = (TextureView) mRootView.findViewById(R.id.preview_content);
1966432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu        mTextureView.addOnLayoutChangeListener(mLayoutListener);
197d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        initIndicators();
1980f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague
1990f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague        mBottomBar = (BottomBar) mRootView.findViewById(R.id.bottom_bar);
2000f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague        mBottomBar.setButtonLayout(R.layout.photo_bottombar_buttons);
2010f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague        mBottomBarMinHeight = activity.getResources()
2020f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague                .getDimensionPixelSize(R.dimen.bottom_bar_height_min);
2030f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague        mBottomBarOptimalHeight = activity.getResources()
2040f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague                .getDimensionPixelSize(R.dimen.bottom_bar_height_optimal);
205d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
206f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        mSurfaceTexture = mTextureView.getSurfaceTexture();
207f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        if (mSurfaceTexture != null) {
208f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu            setTransformMatrix(mTextureView.getWidth(), mTextureView.getHeight());
209f55f3c461c5a6ae6b61fa75562ca01683aa93f9aDoris Liu        }
2100744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
2110744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        ToggleButton focusRingToggle =
2120744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen                (ToggleButton) mRootView.findViewById(R.id.toggle_focus_ring_button);
2130744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        mHideFocusRing = !focusRingToggle.isChecked();
2140744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        focusRingToggle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
2150744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen                @Override
2160744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
2170744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen                    mHideFocusRing = !isChecked;
2180744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen                }
2190744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            });
2200744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        ToggleButton immediateToggle =
2210744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen                (ToggleButton) mRootView.findViewById(R.id.toggle_immediate_capture_button);
2220744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        mImmediateCapture= immediateToggle.isChecked();
2230744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        immediateToggle.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
2240744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen                @Override
2250744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
2260744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen                    mImmediateCapture = isChecked;
2270744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen                }
2280744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            });
2290744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
2300744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        mBottomBar.setBackgroundColor(activity.getResources().getColor(R.color.camera_mode_color));
231638e6f06c877d90b907f66ea9c22b3c6b73c7384Sascha Haeberling        ViewStub faceViewStub = (ViewStub) mRootView
232638e6f06c877d90b907f66ea9c22b3c6b73c7384Sascha Haeberling                .findViewById(R.id.face_view_stub);
233638e6f06c877d90b907f66ea9c22b3c6b73c7384Sascha Haeberling        if (faceViewStub != null) {
234638e6f06c877d90b907f66ea9c22b3c6b73c7384Sascha Haeberling            faceViewStub.inflate();
235638e6f06c877d90b907f66ea9c22b3c6b73c7384Sascha Haeberling            mFaceView = (FaceView) mRootView.findViewById(R.id.face_view);
236638e6f06c877d90b907f66ea9c22b3c6b73c7384Sascha Haeberling            setSurfaceTextureSizeChangedListener(mFaceView);
2376432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu        }
2380f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague
239f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu        mPreviewOverlay = (PreviewOverlay) mRootView.findViewById(R.id.preview_overlay);
2406432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    }
2416432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu
2426432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    public void setSurfaceTextureSizeChangedListener(SurfaceTextureSizeChangedListener listener) {
2436432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu        mSurfaceTextureSizeListener = listener;
2446432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    }
2456432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu
246d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu    public void updatePreviewAspectRatio(float aspectRatio) {
247d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu        if (aspectRatio <= 0) {
248d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu            Log.e(TAG, "Invalid aspect ratio: " + aspectRatio);
249d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu            return;
250d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu        }
251d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu        if (aspectRatio < 1f) {
252d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu            aspectRatio = 1f / aspectRatio;
253d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu        }
254d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu
255d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu        if (mAspectRatio != aspectRatio) {
256d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu            mAspectRatio = aspectRatio;
257d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu            // Update transform matrix with the new aspect ratio.
258d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu            if (mPreviewWidth != 0 && mPreviewHeight != 0) {
259d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu                setTransformMatrix(mPreviewWidth, mPreviewHeight);
260d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu            }
261d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu        }
262d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu    }
263d053a5b2aa8cd9cb09bd40962b305ef34e7d404bDoris Liu
2646432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    private void setTransformMatrix(int width, int height) {
2650f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague        mActivity.getCameraAppUI().adjustPreviewAndBottomBarSize(width, height, mBottomBar,
2660f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague                mAspectRatio, mBottomBarMinHeight, mBottomBarOptimalHeight);
2676432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    }
2686432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu
269b09b53efcd179d55836014dcd054cff6f7d688d8Erin Dahlgren    protected Object getSurfaceTextureLock() {
270b09b53efcd179d55836014dcd054cff6f7d688d8Erin Dahlgren        return mSurfaceTextureLock;
271b09b53efcd179d55836014dcd054cff6f7d688d8Erin Dahlgren    }
272b09b53efcd179d55836014dcd054cff6f7d688d8Erin Dahlgren
273dcccc510652b835fdbd39310a07849af8203052aAngus Kong    @Override
2746432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
275b09b53efcd179d55836014dcd054cff6f7d688d8Erin Dahlgren        synchronized (mSurfaceTextureLock) {
276b09b53efcd179d55836014dcd054cff6f7d688d8Erin Dahlgren            Log.v(TAG, "SurfaceTexture ready.");
277b09b53efcd179d55836014dcd054cff6f7d688d8Erin Dahlgren            mSurfaceTexture = surface;
278b09b53efcd179d55836014dcd054cff6f7d688d8Erin Dahlgren            mController.onPreviewUIReady();
279b09b53efcd179d55836014dcd054cff6f7d688d8Erin Dahlgren            // Workaround for b/11168275, see b/10981460 for more details
280b09b53efcd179d55836014dcd054cff6f7d688d8Erin Dahlgren            if (mPreviewWidth != 0 && mPreviewHeight != 0) {
281b09b53efcd179d55836014dcd054cff6f7d688d8Erin Dahlgren                // Re-apply transform matrix for new surface texture
282b09b53efcd179d55836014dcd054cff6f7d688d8Erin Dahlgren                setTransformMatrix(mPreviewWidth, mPreviewHeight);
283b09b53efcd179d55836014dcd054cff6f7d688d8Erin Dahlgren            }
28418f20b9f460a8e329dd5af1e035d23931e7e1910Doris Liu        }
2856432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    }
286d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
287dcccc510652b835fdbd39310a07849af8203052aAngus Kong    @Override
2886432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
2896432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu        // Ignored, Camera does all the work for us
2906432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    }
2916432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu
292dcccc510652b835fdbd39310a07849af8203052aAngus Kong    @Override
2936432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
294b09b53efcd179d55836014dcd054cff6f7d688d8Erin Dahlgren        synchronized (mSurfaceTextureLock) {
295b09b53efcd179d55836014dcd054cff6f7d688d8Erin Dahlgren            mSurfaceTexture = null;
296b09b53efcd179d55836014dcd054cff6f7d688d8Erin Dahlgren            mController.onPreviewUIDestroyed();
297b09b53efcd179d55836014dcd054cff6f7d688d8Erin Dahlgren            Log.w(TAG, "SurfaceTexture destroyed");
298b09b53efcd179d55836014dcd054cff6f7d688d8Erin Dahlgren            return true;
299b09b53efcd179d55836014dcd054cff6f7d688d8Erin Dahlgren        }
3006432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    }
3016432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu
3027b265a6b2f55c6ae7afc30e63ba324c4084a5d8eztenghui    @Override
3036432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    public void onSurfaceTextureUpdated(SurfaceTexture surface) {
304d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
305d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
306d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public View getRootView() {
307d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        return mRootView;
308d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
309d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
310d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    private void initIndicators() {
3110744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        // TODO init toggle buttons on bottom bar here
312d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
313d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
314e419b1919ed54d8d94d19faec2d02e773ae7ecdbErin Dahlgren    public void onCameraOpened(Camera.Parameters params,
31518e2ef6d2b2d36abcaa7378a0f7df792ecf8ed81Erin Dahlgren            ButtonManager.ButtonCallback cameraCallback,
31618e2ef6d2b2d36abcaa7378a0f7df792ecf8ed81Erin Dahlgren            ButtonManager.ButtonCallback hdrCallback) {
31718e2ef6d2b2d36abcaa7378a0f7df792ecf8ed81Erin Dahlgren        ButtonManager buttonManager = mActivity.getButtonManager();
3188a2933b2c0156b752425b499f3081e4ffc350061Erin Dahlgren        SettingsManager settingsManager = mActivity.getSettingsManager();
3198a2933b2c0156b752425b499f3081e4ffc350061Erin Dahlgren        if (settingsManager.isCameraBackFacing()) {
3208a2933b2c0156b752425b499f3081e4ffc350061Erin Dahlgren            buttonManager.enableButton(ButtonManager.BUTTON_FLASH, R.id.flash_toggle_button,
3218a2933b2c0156b752425b499f3081e4ffc350061Erin Dahlgren                null, R.array.camera_flashmode_icons);
3228a2933b2c0156b752425b499f3081e4ffc350061Erin Dahlgren        } else {
3238a2933b2c0156b752425b499f3081e4ffc350061Erin Dahlgren            buttonManager.disableButton(ButtonManager.BUTTON_FLASH,
3248a2933b2c0156b752425b499f3081e4ffc350061Erin Dahlgren                R.id.flash_toggle_button);
3258a2933b2c0156b752425b499f3081e4ffc350061Erin Dahlgren        }
3268a2933b2c0156b752425b499f3081e4ffc350061Erin Dahlgren        buttonManager.enableButton(ButtonManager.BUTTON_CAMERA, R.id.camera_toggle_button,
32718e2ef6d2b2d36abcaa7378a0f7df792ecf8ed81Erin Dahlgren            cameraCallback, R.array.camera_id_icons);
3288a2933b2c0156b752425b499f3081e4ffc350061Erin Dahlgren        buttonManager.enableButton(ButtonManager.BUTTON_HDRPLUS, R.id.hdr_plus_toggle_button,
32906db742814dd635d100639f977fcfdc904deb778Doris Liu                hdrCallback, R.array.pref_camera_hdr_plus_icons);
330d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
331d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        initializeZoom(params);
332d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
333d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
33429da2db13029f8896018836693139a05d1139362Doris Liu    public void animateCapture(final byte[] jpegData, int orientation, boolean mirror) {
33537f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling        // Decode jpeg byte array and then animate the jpeg
33629da2db13029f8896018836693139a05d1139362Doris Liu        DecodeTask task = new DecodeTask(jpegData, orientation, mirror);
33737f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling        task.execute();
33837f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling    }
33937f3611bbdc787c996a99894dcef7d8fb77e3f7cSascha Haeberling
340d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void initializeControlByIntent() {
341d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        if (mController.isImageCaptureIntent()) {
3426432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu            ViewGroup cameraControls = (ViewGroup) mRootView.findViewById(R.id.camera_controls);
343d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            mActivity.getLayoutInflater().inflate(R.layout.review_module_control, cameraControls);
344d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
3456432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu            mReviewDoneButton = mRootView.findViewById(R.id.btn_done);
3466432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu            mReviewCancelButton = mRootView.findViewById(R.id.btn_cancel);
3476432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu            mReviewRetakeButton = mRootView.findViewById(R.id.btn_retake);
34836e56fba281292255a01ee00b4bee067fa09ab59Doris Liu            mReviewImage = (ImageView) mRootView.findViewById(R.id.review_image);
349d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            mReviewCancelButton.setVisibility(View.VISIBLE);
350d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
351d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            mReviewDoneButton.setOnClickListener(new OnClickListener() {
352d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb                @Override
353d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb                public void onClick(View v) {
354d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb                    mController.onCaptureDone();
355d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb                }
356d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            });
357d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            mReviewCancelButton.setOnClickListener(new OnClickListener() {
358d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb                @Override
359d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb                public void onClick(View v) {
360d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb                    mController.onCaptureCancelled();
361d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb                }
362d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            });
363d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
364d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            mReviewRetakeButton.setOnClickListener(new OnClickListener() {
365d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb                @Override
366d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb                public void onClick(View v) {
367d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb                    mController.onCaptureRetake();
368d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb                }
369d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            });
370d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
371d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
372d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
373d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    // called from onResume but only the first time
374d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public  void initializeFirstTime() {
3750744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
376d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
377d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
378d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    // called from onResume every other time
379d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void initializeSecondTime(Camera.Parameters params) {
380d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        initializeZoom(params);
381d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        if (mController.isImageCaptureIntent()) {
382d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            hidePostCaptureAlert();
383d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
384357b7673f03d9b45d281d585cc3f4f87dc7d727bErin Dahlgren        // Removes pie menu.
385d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
386d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
3876a83d528b09c55ade6ad44b82c81d4476ac57441Doris Liu    public void showLocationDialog() {
388491c628441a58f2dd4b5a5745147552d3f3d9decErin Dahlgren        AlertDialog alert = mActivity.getFirstTimeLocationAlert();
389491c628441a58f2dd4b5a5745147552d3f3d9decErin Dahlgren        alert.show();
3906a83d528b09c55ade6ad44b82c81d4476ac57441Doris Liu    }
3916a83d528b09c55ade6ad44b82c81d4476ac57441Doris Liu
392d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void initializeZoom(Camera.Parameters params) {
393f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu        if ((params == null) || !params.isZoomSupported()) return;
394d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        mZoomMax = params.getMaxZoom();
395d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        mZoomRatios = params.getZoomRatios();
396d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        // Currently we use immediate zoom for fast zooming to get better UX and
397d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        // there is no plan to take advantage of the smooth zoom.
398f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu        // TODO: Need to setup a path to AppUI to do this
399f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu        mPreviewOverlay.setupZoom(mZoomMax, params.getZoom(), mZoomRatios, new ZoomChangeListener());
400d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
401d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
402c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu    public void animateFlash() {
4030f3c4b4fc9ac87d7d4c3d04c3cb3426c711f57eaSpike Sprague        mActivity.startPreCaptureAnimation();
404c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu    }
405c2e9abdcb39a9b8070889ff7a7d829b3eda0c51bDoris Liu
406d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public boolean onBackPressed() {
407d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        // In image capture mode, back button should:
408d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        // 1) if there is any popup, dismiss them, 2) otherwise, get out of
409d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        // image capture
410d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        if (mController.isImageCaptureIntent()) {
411c3679c0961521165499380c77344acc69072b2acDoris Liu            mController.onCaptureCancelled();
412d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            return true;
413d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        } else if (!mController.isCameraIdle()) {
414d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            // ignore backs while we're taking a picture
415d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            return true;
416d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        } else {
417c3679c0961521165499380c77344acc69072b2acDoris Liu            return false;
418d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
419d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
420d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
42136e56fba281292255a01ee00b4bee067fa09ab59Doris Liu    protected void showCapturedImageForReview(byte[] jpegData, int orientation, boolean mirror) {
42236e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        mDecodeTaskForReview = new DecodeImageForReview(jpegData, orientation, mirror);
42336e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        mDecodeTaskForReview.execute();
424b50b5cbfbc0a67db6fc43373363b10381c9c61a3Angus Kong        CameraUtil.fadeIn(mReviewDoneButton);
425d31cdfeb1035df8ba939e877031769f0df247aa6Doris Liu        pauseFaceDetection();
426d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
427d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
428d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    protected void hidePostCaptureAlert() {
42936e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        if (mDecodeTaskForReview != null) {
43036e56fba281292255a01ee00b4bee067fa09ab59Doris Liu            mDecodeTaskForReview.cancel(true);
43136e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        }
43236e56fba281292255a01ee00b4bee067fa09ab59Doris Liu        mReviewImage.setVisibility(View.GONE);
433b50b5cbfbc0a67db6fc43373363b10381c9c61a3Angus Kong        CameraUtil.fadeOut(mReviewDoneButton);
434b50b5cbfbc0a67db6fc43373363b10381c9c61a3Angus Kong        CameraUtil.fadeOut(mReviewRetakeButton);
435d31cdfeb1035df8ba939e877031769f0df247aa6Doris Liu        resumeFaceDetection();
436d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
437d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
438d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void setDisplayOrientation(int orientation) {
439d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        if (mFaceView != null) {
440d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            mFaceView.setDisplayOrientation(orientation);
441d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
442d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
443d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
444d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    // shutter button handling
445d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
446d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public boolean isShutterPressed() {
4470744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        return false;
448d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
449d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
4508890194726507573fd230fba7d4042ed00b363e4Sascha Haeberling    /**
4518890194726507573fd230fba7d4042ed00b363e4Sascha Haeberling     * Enables or disables the shutter button.
4528890194726507573fd230fba7d4042ed00b363e4Sascha Haeberling     */
4536432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    public void enableShutter(boolean enabled) {
4540744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
4556432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    }
456d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
4576432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    public void pressShutterButton() {
4580744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen
4596432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    }
460d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
461f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu    private class ZoomChangeListener implements PreviewOverlay.OnZoomChangedListener {
462d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        @Override
463d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        public void onZoomValueChanged(int index) {
464f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu            mController.onZoomChanged(index);
465d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
466d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
467d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        @Override
468d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        public void onZoomStart() {
469d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
470d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
471d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        @Override
472d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        public void onZoomEnd() {
473d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
474d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
475d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
4766432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu    public void setSwipingEnabled(boolean enable) {
4776432cd65159731a28d9239426b0f0f4d7c44fa98Doris Liu        mActivity.setSwipingEnabled(enable);
478d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
479d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
480dcccc510652b835fdbd39310a07849af8203052aAngus Kong    public SurfaceTexture getSurfaceTexture() {
481d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        return mSurfaceTexture;
482d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
483d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
484d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void showPreferencesToast() {
485d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        if (mNotSelectableToast == null) {
486d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            String str = mActivity.getResources().getString(R.string.not_selectable_in_scene_mode);
487d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb            mNotSelectableToast = Toast.makeText(mActivity, str, Toast.LENGTH_SHORT);
488d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        }
489d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        mNotSelectableToast.show();
490d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
491d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
492d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void onPause() {
493d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        if (mFaceView != null) mFaceView.clear();
494d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
495d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
496d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    // focus UI implementation
497d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    private FocusIndicator getFocusIndicator() {
4980744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        if (mHideFocusRing) {
4990744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            return null;
5000744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        }
501f9e4f8fbd1f761443d7a1eecbb5aa221ed3a06a8Doris Liu        return (mFaceView != null && mFaceView.faceExists()) ? mFaceView : null;
502d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
503d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
504d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    @Override
505d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public boolean hasFaces() {
506d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        return (mFaceView != null && mFaceView.faceExists());
507d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
508d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
509d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void clearFaces() {
5100744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        if (mFaceView != null) {
5110744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            mFaceView.clear();
5120744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        }
513d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
514d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
515d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    @Override
516d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void clearFocus() {
5172441ada50f4bfa3a6c59472ebd3b6339778b8b6bMichael Kolb        FocusIndicator indicator = getFocusIndicator();
5180744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        if (indicator != null) {
5190744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen            indicator.clear();
5200744e4ab3ec5f0270bdad33e7c477f52ba680bbdMarco Nelissen        }
521d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
522d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
523d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    @Override
524d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void setFocusPosition(int x, int y) {
525d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
526d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
527d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    @Override
528d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void onFocusStarted() {
529357b7673f03d9b45d281d585cc3f4f87dc7d727bErin Dahlgren        FocusIndicator indicator = getFocusIndicator();
530357b7673f03d9b45d281d585cc3f4f87dc7d727bErin Dahlgren        if (indicator != null) {
531357b7673f03d9b45d281d585cc3f4f87dc7d727bErin Dahlgren            indicator.showStart();
532357b7673f03d9b45d281d585cc3f4f87dc7d727bErin Dahlgren        }
533d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
534d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
535d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    @Override
536d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void onFocusSucceeded(boolean timeout) {
537357b7673f03d9b45d281d585cc3f4f87dc7d727bErin Dahlgren        FocusIndicator indicator = getFocusIndicator();
538357b7673f03d9b45d281d585cc3f4f87dc7d727bErin Dahlgren        if (indicator != null) {
539357b7673f03d9b45d281d585cc3f4f87dc7d727bErin Dahlgren            indicator.showSuccess(timeout);
540357b7673f03d9b45d281d585cc3f4f87dc7d727bErin Dahlgren        }
541d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
542d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
543d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    @Override
544d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void onFocusFailed(boolean timeout) {
545357b7673f03d9b45d281d585cc3f4f87dc7d727bErin Dahlgren        FocusIndicator indicator = getFocusIndicator();
546357b7673f03d9b45d281d585cc3f4f87dc7d727bErin Dahlgren        if (indicator != null) {
547357b7673f03d9b45d281d585cc3f4f87dc7d727bErin Dahlgren            indicator.showFail(timeout);
548357b7673f03d9b45d281d585cc3f4f87dc7d727bErin Dahlgren        }
549d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
550d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
551d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    @Override
552d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void pauseFaceDetection() {
553d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        if (mFaceView != null) mFaceView.pause();
554d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
555d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
556d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    @Override
557d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void resumeFaceDetection() {
558d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        if (mFaceView != null) mFaceView.resume();
559d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
560d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
561d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    public void onStartFaceDetection(int orientation, boolean mirror) {
562d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        mFaceView.clear();
563d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        mFaceView.setVisibility(View.VISIBLE);
564d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        mFaceView.setDisplayOrientation(orientation);
565d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        mFaceView.setMirror(mirror);
566d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        mFaceView.resume();
567d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
568d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
569d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    @Override
5709e76552adff6ecf8b8e4070ecd61699cb6d18269Angus Kong    public void onFaceDetection(Face[] faces, CameraManager.CameraProxy camera) {
571d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb        mFaceView.setFaces(faces);
572d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb    }
573d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb
574d6954f337e20365fc24ecffdd6f30e17c6b31effMichael Kolb}
575