FocusManager.java revision 9d80a29af1ed57eded5d20af51ef5e704b32b452
1d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li/*
2d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li * Copyright (C) 2011 The Android Open Source Project
3d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li *
4d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li * Licensed under the Apache License, Version 2.0 (the "License");
5d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li * you may not use this file except in compliance with the License.
6d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li * You may obtain a copy of the License at
7d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li *
8d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li *      http://www.apache.org/licenses/LICENSE-2.0
9d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li *
10d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li * Unless required by applicable law or agreed to in writing, software
11d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li * distributed under the License is distributed on an "AS IS" BASIS,
12d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li * See the License for the specific language governing permissions and
14d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li * limitations under the License.
15d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li */
16d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
17d480002ccad05cf992c628c72884091c36cc654cWu-cheng Lipackage com.android.camera;
18d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
19d480002ccad05cf992c628c72884091c36cc654cWu-cheng Liimport com.android.camera.ui.FaceView;
2020b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Liimport com.android.camera.ui.FocusIndicator;
2120b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Liimport com.android.camera.ui.FocusIndicatorView;
22d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
231acf35ce296efc6b3ad823a9500f79f71c545201Wu-cheng Liimport android.content.res.AssetFileDescriptor;
24d480002ccad05cf992c628c72884091c36cc654cWu-cheng Liimport android.graphics.Rect;
25d480002ccad05cf992c628c72884091c36cc654cWu-cheng Liimport android.hardware.Camera.Area;
26d480002ccad05cf992c628c72884091c36cc654cWu-cheng Liimport android.hardware.Camera.Parameters;
27d480002ccad05cf992c628c72884091c36cc654cWu-cheng Liimport android.os.Handler;
28d480002ccad05cf992c628c72884091c36cc654cWu-cheng Liimport android.os.Message;
29d480002ccad05cf992c628c72884091c36cc654cWu-cheng Liimport android.util.Log;
30d480002ccad05cf992c628c72884091c36cc654cWu-cheng Liimport android.view.MotionEvent;
31d480002ccad05cf992c628c72884091c36cc654cWu-cheng Liimport android.view.View;
32d480002ccad05cf992c628c72884091c36cc654cWu-cheng Liimport android.view.ViewGroup;
33d480002ccad05cf992c628c72884091c36cc654cWu-cheng Liimport android.widget.RelativeLayout;
34d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
35d480002ccad05cf992c628c72884091c36cc654cWu-cheng Liimport java.util.ArrayList;
36d480002ccad05cf992c628c72884091c36cc654cWu-cheng Liimport java.util.List;
37d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
38d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li// A class that handles everything about focus in still picture mode.
39d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li// This also handles the metering area because it is the same as focus area.
40d480002ccad05cf992c628c72884091c36cc654cWu-cheng Lipublic class FocusManager {
4158dadc3028b3af2e9895089e1b39ad1ab982ece2Wu-cheng Li    private static final String TAG = "FocusManager";
42d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
43d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private static final int RESET_TOUCH_FOCUS = 0;
44d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private static final int FOCUS_BEEP_VOLUME = 100;
45d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private static final int RESET_TOUCH_FOCUS_DELAY = 3000;
46d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
47d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private int mState = STATE_IDLE;
48d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private static final int STATE_IDLE = 0; // Focus is not active.
49d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private static final int STATE_FOCUSING = 1; // Focus is in progress.
50d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    // Focus is in progress and the camera should take a picture after focus finishes.
51d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private static final int STATE_FOCUSING_SNAP_ON_FINISH = 2;
52d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private static final int STATE_SUCCESS = 3; // Focus finishes and succeeds.
53d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private static final int STATE_FAIL = 4; // Focus finishes and fails.
54d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
55d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private boolean mInitialized;
56d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private boolean mFocusAreaSupported;
571acf35ce296efc6b3ad823a9500f79f71c545201Wu-cheng Li    private SoundPlayer mSoundPlayer;
5820b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li    private View mFocusIndicatorRotateLayout;
5920b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li    private FocusIndicatorView mFocusIndicator;
60d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private View mPreviewFrame;
61d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private FaceView mFaceView;
62bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang    private List<Area> mFocusArea; // focus area in driver format
63bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang    private List<Area> mMeteringArea; // metering area in driver format
64d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private String mFocusMode;
65d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private String mDefaultFocusMode;
66d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private String mOverrideFocusMode;
67d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private Parameters mParameters;
68d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private ComboPreferences mPreferences;
69d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private Handler mHandler;
70d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    Listener mListener;
71d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
72d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public interface Listener {
73d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        public void autoFocus();
74d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        public void cancelAutoFocus();
75d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        public boolean capture();
76d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        public void startFaceDetection();
77d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        public void stopFaceDetection();
78d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        public void setFocusParameters();
79d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
80d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
81d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private class MainHandler extends Handler {
82d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        @Override
83d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        public void handleMessage(Message msg) {
84d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            switch (msg.what) {
85d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                case RESET_TOUCH_FOCUS: {
86d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                    cancelAutoFocus();
87d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                    mListener.startFaceDetection();
88d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                    break;
89d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                }
90d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            }
91d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        }
92d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
93d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
9458dadc3028b3af2e9895089e1b39ad1ab982ece2Wu-cheng Li    public FocusManager(ComboPreferences preferences, String defaultFocusMode) {
95d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mPreferences = preferences;
96d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mDefaultFocusMode = defaultFocusMode;
9758dadc3028b3af2e9895089e1b39ad1ab982ece2Wu-cheng Li        mHandler = new MainHandler();
9858dadc3028b3af2e9895089e1b39ad1ab982ece2Wu-cheng Li    }
9958dadc3028b3af2e9895089e1b39ad1ab982ece2Wu-cheng Li
10058dadc3028b3af2e9895089e1b39ad1ab982ece2Wu-cheng Li    // This has to be initialized before initialize().
10158dadc3028b3af2e9895089e1b39ad1ab982ece2Wu-cheng Li    public void initializeParameters(Parameters parameters) {
102d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mParameters = parameters;
103d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mFocusAreaSupported = (mParameters.getMaxNumFocusAreas() > 0
104d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                && isSupported(Parameters.FOCUS_MODE_AUTO,
105d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                        mParameters.getSupportedFocusModes()));
106d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
107d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
10820b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li    public void initialize(View focusIndicatorRotate, View previewFrame,
109d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            FaceView faceView, Listener listener) {
11020b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li        mFocusIndicatorRotateLayout = focusIndicatorRotate;
11120b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li        mFocusIndicator = (FocusIndicatorView) focusIndicatorRotate.findViewById(
11220b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li                R.id.focus_indicator);
113d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mPreviewFrame = previewFrame;
114d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mFaceView = faceView;
115d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mListener = listener;
11658dadc3028b3af2e9895089e1b39ad1ab982ece2Wu-cheng Li        if (mParameters != null) {
11758dadc3028b3af2e9895089e1b39ad1ab982ece2Wu-cheng Li            mInitialized = true;
11858dadc3028b3af2e9895089e1b39ad1ab982ece2Wu-cheng Li        } else {
11958dadc3028b3af2e9895089e1b39ad1ab982ece2Wu-cheng Li            Log.e(TAG, "mParameters is not initialized.");
12058dadc3028b3af2e9895089e1b39ad1ab982ece2Wu-cheng Li        }
121d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
122d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
123d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public void doFocus(boolean pressed) {
124d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        if (!mInitialized) return;
125d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
126d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        if (!(getFocusMode().equals(Parameters.FOCUS_MODE_INFINITY)
127d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                || getFocusMode().equals(Parameters.FOCUS_MODE_FIXED)
128d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                || getFocusMode().equals(Parameters.FOCUS_MODE_EDOF))) {
129d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            if (pressed) {  // Focus key down.
130d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                // Do not focus if touch focus has been triggered.
131d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                if (mState != STATE_SUCCESS && mState != STATE_FAIL) {
132d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                    autoFocus();
133d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                }
134d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            } else {  // Focus key up.
135d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                // User releases half-pressed focus key.
136d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                if (mState == STATE_FOCUSING || mState == STATE_SUCCESS
137d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                        || mState == STATE_FAIL) {
138d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                    cancelAutoFocus();
139d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                }
140d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            }
141d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        }
142d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
143d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
144d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public void doSnap() {
145d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        if (!mInitialized) return;
146d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
147d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        // If the user has half-pressed the shutter and focus is completed, we
148d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        // can take the photo right away. If the focus mode is infinity, we can
149d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        // also take the photo.
150d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        if (getFocusMode().equals(Parameters.FOCUS_MODE_INFINITY)
151d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                || getFocusMode().equals(Parameters.FOCUS_MODE_FIXED)
152d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                || getFocusMode().equals(Parameters.FOCUS_MODE_EDOF)
153d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                || (mState == STATE_SUCCESS
154d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                || mState == STATE_FAIL)) {
155d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            capture();
156d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        } else if (mState == STATE_FOCUSING) {
157d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // Half pressing the shutter (i.e. the focus button event) will
158d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // already have requested AF for us, so just request capture on
159d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // focus here.
160d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            mState = STATE_FOCUSING_SNAP_ON_FINISH;
161d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        } else if (mState == STATE_IDLE) {
1629d80a29af1ed57eded5d20af51ef5e704b32b452Chih-Chung Chang            // We didn't do focus. This can happen if the user press focus key
1639d80a29af1ed57eded5d20af51ef5e704b32b452Chih-Chung Chang            // while the snapshot is still in progress. The user probably wants
1649d80a29af1ed57eded5d20af51ef5e704b32b452Chih-Chung Chang            // the next snapshot as soon as possible, so we just do a snapshot
1659d80a29af1ed57eded5d20af51ef5e704b32b452Chih-Chung Chang            // without focusing again.
1669d80a29af1ed57eded5d20af51ef5e704b32b452Chih-Chung Chang            capture();
167d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        }
168d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
169d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
170d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public void onShutter() {
171d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        resetTouchFocus();
172d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        updateFocusUI();
173d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
174d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
175d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public void onAutoFocus(boolean focused) {
1766bc0f740f5d7fa6eb8aa8a4ba7dd3ab4dca999d4Wu-cheng Li        if (mState == STATE_FOCUSING_SNAP_ON_FINISH) {
177d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // Take the picture no matter focus succeeds or fails. No need
178d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // to play the AF sound if we're about to play the shutter
179d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // sound.
180d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            if (focused) {
181d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                mState = STATE_SUCCESS;
182d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            } else {
183d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                mState = STATE_FAIL;
184d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            }
185d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            updateFocusUI();
186d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            capture();
187d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        } else if (mState == STATE_FOCUSING) {
188d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // This happens when (1) user is half-pressing the focus key or
189d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // (2) touch focus is triggered. Play the focus tone. Do not
190d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // take the picture now.
191d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            if (focused) {
192d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                mState = STATE_SUCCESS;
193a7a50a45c75585e350eb730574b1e531468e8b18Wu-cheng Li                // Do not play the sound in continuous autofocus mode. It does
194a7a50a45c75585e350eb730574b1e531468e8b18Wu-cheng Li                // not do a full scan. The focus callback arrives before doSnap
195a7a50a45c75585e350eb730574b1e531468e8b18Wu-cheng Li                // so the state is always STATE_FOCUSING.
196a7a50a45c75585e350eb730574b1e531468e8b18Wu-cheng Li                if (!Parameters.FOCUS_MODE_CONTINUOUS_PICTURE.equals(mFocusMode)
1971acf35ce296efc6b3ad823a9500f79f71c545201Wu-cheng Li                        && mSoundPlayer != null) {
1981acf35ce296efc6b3ad823a9500f79f71c545201Wu-cheng Li                    mSoundPlayer.play();
199d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                }
200d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            } else {
201d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                mState = STATE_FAIL;
202d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            }
203d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            updateFocusUI();
204d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // If this is triggered by touch focus, cancel focus after a
205d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // while.
206bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang            if (mFocusArea != null) {
207d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                mHandler.sendEmptyMessageDelayed(RESET_TOUCH_FOCUS, RESET_TOUCH_FOCUS_DELAY);
208d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            }
209d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        } else if (mState == STATE_IDLE) {
210d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // User has released the focus key before focus completes.
211d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // Do nothing.
212d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        }
213d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
214d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
215d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public boolean onTouch(MotionEvent e) {
216d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        if (!mInitialized || mState == STATE_FOCUSING_SNAP_ON_FINISH) return false;
217d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
218d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        // Let users be able to cancel previous touch focus.
219bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        if ((mFocusArea != null) && (mState == STATE_FOCUSING ||
220620e427c0aa990458d39b43477675b768d360327Wu-cheng Li                    mState == STATE_SUCCESS || mState == STATE_FAIL)) {
221d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            cancelAutoFocus();
222d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        }
223d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
224d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        // Initialize variables.
225d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        int x = Math.round(e.getX());
226d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        int y = Math.round(e.getY());
22720b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li        int focusWidth = mFocusIndicatorRotateLayout.getWidth();
22820b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li        int focusHeight = mFocusIndicatorRotateLayout.getHeight();
229d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        int previewWidth = mPreviewFrame.getWidth();
230d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        int previewHeight = mPreviewFrame.getHeight();
231bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        if (mFocusArea == null) {
232bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang            mFocusArea = new ArrayList<Area>();
233bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang            mFocusArea.add(new Area(new Rect(), 1));
234bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang            mMeteringArea = new ArrayList<Area>();
235bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang            mMeteringArea.add(new Area(new Rect(), 1));
236d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        }
237d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
238bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        // Convert the coordinates to driver format.
239bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        // AE area is bigger because exposure is sensitive and
240bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        // easy to over- or underexposure if area is too small.
241bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        calculateTapArea(focusWidth, focusHeight, 1, x, y, previewWidth, previewHeight,
242bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang                mFocusArea.get(0).rect);
243bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        calculateTapArea(focusWidth, focusHeight, 1.5, x, y, previewWidth, previewHeight,
244bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang                mMeteringArea.get(0).rect);
245d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
24620b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li        // Use margin to set the focus indicator to the touched area.
247d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        RelativeLayout.LayoutParams p =
24820b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li                (RelativeLayout.LayoutParams) mFocusIndicatorRotateLayout.getLayoutParams();
249d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        int left = Util.clamp(x - focusWidth / 2, 0, previewWidth - focusWidth);
250d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        int top = Util.clamp(y - focusHeight / 2, 0, previewHeight - focusHeight);
251d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        p.setMargins(left, top, 0, 0);
252d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        // Disable "center" rule because we no longer want to put it in the center.
253d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        int[] rules = p.getRules();
254d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        rules[RelativeLayout.CENTER_IN_PARENT] = 0;
25520b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li        mFocusIndicatorRotateLayout.requestLayout();
256d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
257d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        // Stop face detection because we want to specify focus and metering area.
258d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mListener.stopFaceDetection();
259d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
260d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        // Set the focus area and metering area.
261d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mListener.setFocusParameters();
262d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        if (mFocusAreaSupported && (e.getAction() == MotionEvent.ACTION_UP)) {
263d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            autoFocus();
26420b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li        } else {  // Just show the indicator in all other cases.
265d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            updateFocusUI();
266d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // Reset the metering area in 3 seconds.
267d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            mHandler.removeMessages(RESET_TOUCH_FOCUS);
268d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            mHandler.sendEmptyMessageDelayed(RESET_TOUCH_FOCUS, RESET_TOUCH_FOCUS_DELAY);
269d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        }
270d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
271d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        return true;
272d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
273d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
274d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public void onPreviewStarted() {
275d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mState = STATE_IDLE;
276d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
277d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
278d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public void onPreviewStopped() {
279d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mState = STATE_IDLE;
280d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        resetTouchFocus();
281d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        // If auto focus was in progress, it would have been canceled.
282d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        updateFocusUI();
283d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
284d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
285d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public void onCameraReleased() {
286d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        onPreviewStopped();
287d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
288d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
289d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private void autoFocus() {
290d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        Log.v(TAG, "Start autofocus.");
291d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mListener.autoFocus();
292d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mState = STATE_FOCUSING;
293d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        // Pause the face view because the driver will keep sending face
294d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        // callbacks after the focus completes.
295d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        if (mFaceView != null) mFaceView.pause();
296d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        updateFocusUI();
297d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mHandler.removeMessages(RESET_TOUCH_FOCUS);
298d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
299d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
300d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private void cancelAutoFocus() {
301d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        Log.v(TAG, "Cancel autofocus.");
3025d4972e63a1f81139c6503fd433f06c77276fc38Sundar Raman
3035d4972e63a1f81139c6503fd433f06c77276fc38Sundar Raman        // Reset the tap area before calling mListener.cancelAutofocus.
3045d4972e63a1f81139c6503fd433f06c77276fc38Sundar Raman        // Otherwise, focus mode stays at auto and the tap area passed to the
3055d4972e63a1f81139c6503fd433f06c77276fc38Sundar Raman        // driver is not reset.
3065d4972e63a1f81139c6503fd433f06c77276fc38Sundar Raman        resetTouchFocus();
307d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mListener.cancelAutoFocus();
308d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        if (mFaceView != null) mFaceView.resume();
309d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mState = STATE_IDLE;
310d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        updateFocusUI();
311d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mHandler.removeMessages(RESET_TOUCH_FOCUS);
312d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
313d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
314d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private void capture() {
315d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        if (mListener.capture()) {
316d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            mState = STATE_IDLE;
317d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            mHandler.removeMessages(RESET_TOUCH_FOCUS);
318d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        }
319d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
320d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
3211acf35ce296efc6b3ad823a9500f79f71c545201Wu-cheng Li    public void initializeSoundPlayer(AssetFileDescriptor fd) {
3221acf35ce296efc6b3ad823a9500f79f71c545201Wu-cheng Li        mSoundPlayer = new SoundPlayer(fd);
323d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
324d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
3251acf35ce296efc6b3ad823a9500f79f71c545201Wu-cheng Li    public void releaseSoundPlayer() {
3261acf35ce296efc6b3ad823a9500f79f71c545201Wu-cheng Li        if (mSoundPlayer != null) {
3271acf35ce296efc6b3ad823a9500f79f71c545201Wu-cheng Li            mSoundPlayer.release();
3281acf35ce296efc6b3ad823a9500f79f71c545201Wu-cheng Li            mSoundPlayer = null;
329d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        }
330d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
331d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
3321acf35ce296efc6b3ad823a9500f79f71c545201Wu-cheng Li
33358dadc3028b3af2e9895089e1b39ad1ab982ece2Wu-cheng Li    // This can only be called after mParameters is initialized.
334d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public String getFocusMode() {
335d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        if (mOverrideFocusMode != null) return mOverrideFocusMode;
336d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
337bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        if (mFocusAreaSupported && mFocusArea != null) {
3386bc0f740f5d7fa6eb8aa8a4ba7dd3ab4dca999d4Wu-cheng Li            // Always use autofocus in tap-to-focus.
339d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            mFocusMode = Parameters.FOCUS_MODE_AUTO;
340d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        } else {
341d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // The default is continuous autofocus.
342d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            mFocusMode = mPreferences.getString(
343d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                    CameraSettings.KEY_FOCUS_MODE, mDefaultFocusMode);
344d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        }
345d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        if (!isSupported(mFocusMode, mParameters.getSupportedFocusModes())) {
346d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // For some reasons, the driver does not support the current
347d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // focus mode. Fall back to auto.
348d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            if (isSupported(Parameters.FOCUS_MODE_AUTO,
349d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                    mParameters.getSupportedFocusModes())) {
350d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                mFocusMode = Parameters.FOCUS_MODE_AUTO;
351d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            } else {
352d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                mFocusMode = mParameters.getFocusMode();
353d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            }
354d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        }
355d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        return mFocusMode;
356d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
357d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
358bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang    public List<Area> getFocusAreas() {
359bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        return mFocusArea;
360bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang    }
361bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang
362bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang    public List<Area> getMeteringAreas() {
363bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        return mMeteringArea;
364d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
365d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
366d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public void updateFocusUI() {
367d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        if (!mInitialized) return;
368d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
36920b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li        // Set the length of focus indicator according to preview frame size.
370d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        int len = Math.min(mPreviewFrame.getWidth(), mPreviewFrame.getHeight()) / 4;
371bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        ViewGroup.LayoutParams layout = mFocusIndicator.getLayoutParams();
372d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        layout.width = len;
373d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        layout.height = len;
374d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
37520b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li        // Show only focus indicator or face indicator.
37620b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li        boolean faceExists = (mFaceView != null && mFaceView.faceExists());
37720b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li        FocusIndicator focusIndicator = (faceExists) ? mFaceView : mFocusIndicator;
37820b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li
379d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        if (mState == STATE_IDLE) {
380bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang            if (mFocusArea == null) {
38120b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li                focusIndicator.clear();
382d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            } else {
38320b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li                // Users touch on the preview and the indicator represents the
384d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                // metering area. Either focus area is not supported or
385d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                // autoFocus call is not required.
38620b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li                focusIndicator.showStart();
387d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            }
38820b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li        } else if (mState == STATE_FOCUSING || mState == STATE_FOCUSING_SNAP_ON_FINISH) {
38920b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li            focusIndicator.showStart();
390a7a50a45c75585e350eb730574b1e531468e8b18Wu-cheng Li        } else {
391a7a50a45c75585e350eb730574b1e531468e8b18Wu-cheng Li            // In CAF, do not show success or failure because it only returns
392a7a50a45c75585e350eb730574b1e531468e8b18Wu-cheng Li            // the focus status. It does not do a full scan. So the result is
393a7a50a45c75585e350eb730574b1e531468e8b18Wu-cheng Li            // failure most of the time.
394a7a50a45c75585e350eb730574b1e531468e8b18Wu-cheng Li            if (Parameters.FOCUS_MODE_CONTINUOUS_PICTURE.equals(mFocusMode)) {
395a7a50a45c75585e350eb730574b1e531468e8b18Wu-cheng Li                focusIndicator.showStart();
396a7a50a45c75585e350eb730574b1e531468e8b18Wu-cheng Li            } else if (mState == STATE_SUCCESS) {
397a7a50a45c75585e350eb730574b1e531468e8b18Wu-cheng Li                focusIndicator.showSuccess();
398a7a50a45c75585e350eb730574b1e531468e8b18Wu-cheng Li            } else if (mState == STATE_FAIL) {
399a7a50a45c75585e350eb730574b1e531468e8b18Wu-cheng Li                focusIndicator.showFail();
400a7a50a45c75585e350eb730574b1e531468e8b18Wu-cheng Li            }
401d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        }
402d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
403d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
404d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public void resetTouchFocus() {
405d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        if (!mInitialized) return;
406d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
40720b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li        // Put focus indicator to the center.
408d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        RelativeLayout.LayoutParams p =
40920b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li                (RelativeLayout.LayoutParams) mFocusIndicatorRotateLayout.getLayoutParams();
410d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        int[] rules = p.getRules();
411d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        rules[RelativeLayout.CENTER_IN_PARENT] = RelativeLayout.TRUE;
412d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        p.setMargins(0, 0, 0, 0);
413d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
414bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        mFocusArea = null;
415bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        mMeteringArea = null;
416bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang    }
417bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang
418bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang    public void calculateTapArea(int focusWidth, int focusHeight, double areaMultiple,
419bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang            int x, int y, int previewWidth, int previewHeight, Rect rect) {
420bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        int areaWidth = (int)(focusWidth * areaMultiple);
421bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        int areaHeight = (int)(focusHeight * areaMultiple);
422bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        int areaLeft = Util.clamp(x - areaWidth / 2, 0, previewWidth - areaWidth);
423bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        int areaTop = Util.clamp(y - areaHeight / 2, 0, previewHeight - areaHeight);
424bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        convertToFocusArea(areaLeft, areaTop, areaWidth, areaHeight, previewWidth, previewHeight,
425bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang                rect);
426d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
427d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
428d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    // Convert the touch point to the focus area in driver format.
429d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public static void convertToFocusArea(int left, int top, int focusWidth, int focusHeight,
430d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            int previewWidth, int previewHeight, Rect rect) {
431d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        rect.left = Math.round((float) left / previewWidth * 2000 - 1000);
432d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        rect.top = Math.round((float) top / previewHeight * 2000 - 1000);
433d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        rect.right = Math.round((float) (left + focusWidth) / previewWidth * 2000 - 1000);
434d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        rect.bottom = Math.round((float) (top + focusHeight) / previewHeight * 2000 - 1000);
435d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
436d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
437d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public boolean isFocusCompleted() {
438d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        return mState == STATE_SUCCESS || mState == STATE_FAIL;
439d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
440d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
441d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public void removeMessages() {
442d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mHandler.removeMessages(RESET_TOUCH_FOCUS);
443d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
444d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
445d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public void overrideFocusMode(String focusMode) {
446d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mOverrideFocusMode = focusMode;
447d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
448d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
449d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private static boolean isSupported(String value, List<String> supported) {
450d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        return supported == null ? false : supported.indexOf(value) >= 0;
451d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
452d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li}
453