FocusManager.java revision a7a50a45c75585e350eb730574b1e531468e8b18
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
23d480002ccad05cf992c628c72884091c36cc654cWu-cheng Liimport android.graphics.Rect;
24d480002ccad05cf992c628c72884091c36cc654cWu-cheng Liimport android.hardware.Camera.Area;
25d480002ccad05cf992c628c72884091c36cc654cWu-cheng Liimport android.hardware.Camera.Parameters;
26d480002ccad05cf992c628c72884091c36cc654cWu-cheng Liimport android.media.AudioManager;
27d480002ccad05cf992c628c72884091c36cc654cWu-cheng Liimport android.media.ToneGenerator;
28d480002ccad05cf992c628c72884091c36cc654cWu-cheng Liimport android.os.Handler;
29d480002ccad05cf992c628c72884091c36cc654cWu-cheng Liimport android.os.Message;
30d480002ccad05cf992c628c72884091c36cc654cWu-cheng Liimport android.util.Log;
31d480002ccad05cf992c628c72884091c36cc654cWu-cheng Liimport android.view.MotionEvent;
32d480002ccad05cf992c628c72884091c36cc654cWu-cheng Liimport android.view.View;
33d480002ccad05cf992c628c72884091c36cc654cWu-cheng Liimport android.view.ViewGroup;
34d480002ccad05cf992c628c72884091c36cc654cWu-cheng Liimport android.widget.RelativeLayout;
35d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
36d480002ccad05cf992c628c72884091c36cc654cWu-cheng Liimport java.util.ArrayList;
37d480002ccad05cf992c628c72884091c36cc654cWu-cheng Liimport java.util.List;
38d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
39d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li// A class that handles everything about focus in still picture mode.
40d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li// This also handles the metering area because it is the same as focus area.
41d480002ccad05cf992c628c72884091c36cc654cWu-cheng Lipublic class FocusManager {
4258dadc3028b3af2e9895089e1b39ad1ab982ece2Wu-cheng Li    private static final String TAG = "FocusManager";
43d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
44d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private static final int RESET_TOUCH_FOCUS = 0;
45d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private static final int FOCUS_BEEP_VOLUME = 100;
46d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private static final int RESET_TOUCH_FOCUS_DELAY = 3000;
47d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
48d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private int mState = STATE_IDLE;
49d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private static final int STATE_IDLE = 0; // Focus is not active.
50d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private static final int STATE_FOCUSING = 1; // Focus is in progress.
51d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    // Focus is in progress and the camera should take a picture after focus finishes.
52d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private static final int STATE_FOCUSING_SNAP_ON_FINISH = 2;
53d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private static final int STATE_SUCCESS = 3; // Focus finishes and succeeds.
54d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private static final int STATE_FAIL = 4; // Focus finishes and fails.
55d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
56d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private boolean mInitialized;
57d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private boolean mFocusAreaSupported;
58d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private ToneGenerator mFocusToneGenerator;
5920b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li    private View mFocusIndicatorRotateLayout;
6020b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li    private FocusIndicatorView mFocusIndicator;
61d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private View mPreviewFrame;
62d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private FaceView mFaceView;
63bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang    private List<Area> mFocusArea; // focus area in driver format
64bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang    private List<Area> mMeteringArea; // metering area in driver format
65d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private String mFocusMode;
66d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private String mDefaultFocusMode;
67d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private String mOverrideFocusMode;
68d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private Parameters mParameters;
69d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private ComboPreferences mPreferences;
70d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private Handler mHandler;
71d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    Listener mListener;
72d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
73d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public interface Listener {
74d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        public void autoFocus();
75d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        public void cancelAutoFocus();
76d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        public boolean capture();
77d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        public void startFaceDetection();
78d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        public void stopFaceDetection();
79d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        public void setFocusParameters();
80d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
81d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
82d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private class MainHandler extends Handler {
83d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        @Override
84d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        public void handleMessage(Message msg) {
85d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            switch (msg.what) {
86d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                case RESET_TOUCH_FOCUS: {
87d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                    cancelAutoFocus();
88d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                    mListener.startFaceDetection();
89d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                    break;
90d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                }
91d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            }
92d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        }
93d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
94d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
9558dadc3028b3af2e9895089e1b39ad1ab982ece2Wu-cheng Li    public FocusManager(ComboPreferences preferences, String defaultFocusMode) {
96d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mPreferences = preferences;
97d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mDefaultFocusMode = defaultFocusMode;
9858dadc3028b3af2e9895089e1b39ad1ab982ece2Wu-cheng Li        mHandler = new MainHandler();
9958dadc3028b3af2e9895089e1b39ad1ab982ece2Wu-cheng Li    }
10058dadc3028b3af2e9895089e1b39ad1ab982ece2Wu-cheng Li
10158dadc3028b3af2e9895089e1b39ad1ab982ece2Wu-cheng Li    // This has to be initialized before initialize().
10258dadc3028b3af2e9895089e1b39ad1ab982ece2Wu-cheng Li    public void initializeParameters(Parameters parameters) {
103d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mParameters = parameters;
104d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mFocusAreaSupported = (mParameters.getMaxNumFocusAreas() > 0
105d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                && isSupported(Parameters.FOCUS_MODE_AUTO,
106d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                        mParameters.getSupportedFocusModes()));
107d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
108d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
10920b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li    public void initialize(View focusIndicatorRotate, View previewFrame,
110d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            FaceView faceView, Listener listener) {
11120b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li        mFocusIndicatorRotateLayout = focusIndicatorRotate;
11220b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li        mFocusIndicator = (FocusIndicatorView) focusIndicatorRotate.findViewById(
11320b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li                R.id.focus_indicator);
114d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mPreviewFrame = previewFrame;
115d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mFaceView = faceView;
116d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mListener = listener;
11758dadc3028b3af2e9895089e1b39ad1ab982ece2Wu-cheng Li        if (mParameters != null) {
11858dadc3028b3af2e9895089e1b39ad1ab982ece2Wu-cheng Li            mInitialized = true;
11958dadc3028b3af2e9895089e1b39ad1ab982ece2Wu-cheng Li        } else {
12058dadc3028b3af2e9895089e1b39ad1ab982ece2Wu-cheng Li            Log.e(TAG, "mParameters is not initialized.");
12158dadc3028b3af2e9895089e1b39ad1ab982ece2Wu-cheng Li        }
122d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
123d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
124d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public void doFocus(boolean pressed) {
125d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        if (!mInitialized) return;
126d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
127d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        if (!(getFocusMode().equals(Parameters.FOCUS_MODE_INFINITY)
128d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                || getFocusMode().equals(Parameters.FOCUS_MODE_FIXED)
129d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                || getFocusMode().equals(Parameters.FOCUS_MODE_EDOF))) {
130d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            if (pressed) {  // Focus key down.
131d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                // Do not focus if touch focus has been triggered.
132d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                if (mState != STATE_SUCCESS && mState != STATE_FAIL) {
133d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                    autoFocus();
134d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                }
135d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            } else {  // Focus key up.
136d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                // User releases half-pressed focus key.
137d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                if (mState == STATE_FOCUSING || mState == STATE_SUCCESS
138d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                        || mState == STATE_FAIL) {
139d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                    cancelAutoFocus();
140d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                }
141d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            }
142d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        }
143d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
144d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
145d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public void doSnap() {
146d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        if (!mInitialized) return;
147d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
148d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        // If the user has half-pressed the shutter and focus is completed, we
149d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        // can take the photo right away. If the focus mode is infinity, we can
150d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        // also take the photo.
151d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        if (getFocusMode().equals(Parameters.FOCUS_MODE_INFINITY)
152d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                || getFocusMode().equals(Parameters.FOCUS_MODE_FIXED)
153d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                || getFocusMode().equals(Parameters.FOCUS_MODE_EDOF)
154d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                || (mState == STATE_SUCCESS
155d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                || mState == STATE_FAIL)) {
156d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            capture();
157d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        } else if (mState == STATE_FOCUSING) {
158d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // Half pressing the shutter (i.e. the focus button event) will
159d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // already have requested AF for us, so just request capture on
160d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // focus here.
161d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            mState = STATE_FOCUSING_SNAP_ON_FINISH;
162d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        } else if (mState == STATE_IDLE) {
163d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // Focus key down event is dropped for some reasons. Just ignore.
164d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        }
165d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
166d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
167d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public void onShutter() {
168d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        resetTouchFocus();
169d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        updateFocusUI();
170d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
171d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
172d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public void onAutoFocus(boolean focused) {
1736bc0f740f5d7fa6eb8aa8a4ba7dd3ab4dca999d4Wu-cheng Li        if (mState == STATE_FOCUSING_SNAP_ON_FINISH) {
174d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // Take the picture no matter focus succeeds or fails. No need
175d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // to play the AF sound if we're about to play the shutter
176d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // sound.
177d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            if (focused) {
178d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                mState = STATE_SUCCESS;
179d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            } else {
180d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                mState = STATE_FAIL;
181d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            }
182d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            updateFocusUI();
183d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            capture();
184d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        } else if (mState == STATE_FOCUSING) {
185d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // This happens when (1) user is half-pressing the focus key or
186d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // (2) touch focus is triggered. Play the focus tone. Do not
187d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // take the picture now.
188d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            if (focused) {
189d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                mState = STATE_SUCCESS;
190a7a50a45c75585e350eb730574b1e531468e8b18Wu-cheng Li                // Do not play the sound in continuous autofocus mode. It does
191a7a50a45c75585e350eb730574b1e531468e8b18Wu-cheng Li                // not do a full scan. The focus callback arrives before doSnap
192a7a50a45c75585e350eb730574b1e531468e8b18Wu-cheng Li                // so the state is always STATE_FOCUSING.
193a7a50a45c75585e350eb730574b1e531468e8b18Wu-cheng Li                if (!Parameters.FOCUS_MODE_CONTINUOUS_PICTURE.equals(mFocusMode)
194a7a50a45c75585e350eb730574b1e531468e8b18Wu-cheng Li                        && mFocusToneGenerator != null) {
195d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                    mFocusToneGenerator.startTone(ToneGenerator.TONE_PROP_BEEP2);
196d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                }
197d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            } else {
198d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                mState = STATE_FAIL;
199d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            }
200d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            updateFocusUI();
201d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // If this is triggered by touch focus, cancel focus after a
202d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // while.
203bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang            if (mFocusArea != null) {
204d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                mHandler.sendEmptyMessageDelayed(RESET_TOUCH_FOCUS, RESET_TOUCH_FOCUS_DELAY);
205d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            }
206d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        } else if (mState == STATE_IDLE) {
207d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // User has released the focus key before focus completes.
208d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // Do nothing.
209d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        }
210d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
211d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
212d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public boolean onTouch(MotionEvent e) {
213d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        if (!mInitialized || mState == STATE_FOCUSING_SNAP_ON_FINISH) return false;
214d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
215d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        // Let users be able to cancel previous touch focus.
216bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        if ((mFocusArea != null) && (mState == STATE_FOCUSING ||
217620e427c0aa990458d39b43477675b768d360327Wu-cheng Li                    mState == STATE_SUCCESS || mState == STATE_FAIL)) {
218d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            cancelAutoFocus();
219d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        }
220d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
221d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        // Initialize variables.
222d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        int x = Math.round(e.getX());
223d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        int y = Math.round(e.getY());
22420b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li        int focusWidth = mFocusIndicatorRotateLayout.getWidth();
22520b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li        int focusHeight = mFocusIndicatorRotateLayout.getHeight();
226d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        int previewWidth = mPreviewFrame.getWidth();
227d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        int previewHeight = mPreviewFrame.getHeight();
228bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        if (mFocusArea == null) {
229bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang            mFocusArea = new ArrayList<Area>();
230bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang            mFocusArea.add(new Area(new Rect(), 1));
231bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang            mMeteringArea = new ArrayList<Area>();
232bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang            mMeteringArea.add(new Area(new Rect(), 1));
233d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        }
234d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
235bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        // Convert the coordinates to driver format.
236bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        // AE area is bigger because exposure is sensitive and
237bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        // easy to over- or underexposure if area is too small.
238bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        calculateTapArea(focusWidth, focusHeight, 1, x, y, previewWidth, previewHeight,
239bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang                mFocusArea.get(0).rect);
240bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        calculateTapArea(focusWidth, focusHeight, 1.5, x, y, previewWidth, previewHeight,
241bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang                mMeteringArea.get(0).rect);
242d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
24320b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li        // Use margin to set the focus indicator to the touched area.
244d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        RelativeLayout.LayoutParams p =
24520b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li                (RelativeLayout.LayoutParams) mFocusIndicatorRotateLayout.getLayoutParams();
246d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        int left = Util.clamp(x - focusWidth / 2, 0, previewWidth - focusWidth);
247d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        int top = Util.clamp(y - focusHeight / 2, 0, previewHeight - focusHeight);
248d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        p.setMargins(left, top, 0, 0);
249d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        // Disable "center" rule because we no longer want to put it in the center.
250d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        int[] rules = p.getRules();
251d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        rules[RelativeLayout.CENTER_IN_PARENT] = 0;
25220b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li        mFocusIndicatorRotateLayout.requestLayout();
253d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
254d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        // Stop face detection because we want to specify focus and metering area.
255d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mListener.stopFaceDetection();
256d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
257d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        // Set the focus area and metering area.
258d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mListener.setFocusParameters();
259d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        if (mFocusAreaSupported && (e.getAction() == MotionEvent.ACTION_UP)) {
260d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            autoFocus();
26120b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li        } else {  // Just show the indicator in all other cases.
262d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            updateFocusUI();
263d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // Reset the metering area in 3 seconds.
264d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            mHandler.removeMessages(RESET_TOUCH_FOCUS);
265d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            mHandler.sendEmptyMessageDelayed(RESET_TOUCH_FOCUS, RESET_TOUCH_FOCUS_DELAY);
266d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        }
267d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
268d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        return true;
269d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
270d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
271d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public void onPreviewStarted() {
272d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mState = STATE_IDLE;
273d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
274d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
275d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public void onPreviewStopped() {
276d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mState = STATE_IDLE;
277d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        resetTouchFocus();
278d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        // If auto focus was in progress, it would have been canceled.
279d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        updateFocusUI();
280d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
281d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
282d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public void onCameraReleased() {
283d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        onPreviewStopped();
284d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
285d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
286d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private void autoFocus() {
287d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        Log.v(TAG, "Start autofocus.");
288d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mListener.autoFocus();
289d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mState = STATE_FOCUSING;
290d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        // Pause the face view because the driver will keep sending face
291d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        // callbacks after the focus completes.
292d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        if (mFaceView != null) mFaceView.pause();
293d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        updateFocusUI();
294d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mHandler.removeMessages(RESET_TOUCH_FOCUS);
295d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
296d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
297d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private void cancelAutoFocus() {
298d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        Log.v(TAG, "Cancel autofocus.");
2995d4972e63a1f81139c6503fd433f06c77276fc38Sundar Raman
3005d4972e63a1f81139c6503fd433f06c77276fc38Sundar Raman        // Reset the tap area before calling mListener.cancelAutofocus.
3015d4972e63a1f81139c6503fd433f06c77276fc38Sundar Raman        // Otherwise, focus mode stays at auto and the tap area passed to the
3025d4972e63a1f81139c6503fd433f06c77276fc38Sundar Raman        // driver is not reset.
3035d4972e63a1f81139c6503fd433f06c77276fc38Sundar Raman        resetTouchFocus();
304d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mListener.cancelAutoFocus();
305d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        if (mFaceView != null) mFaceView.resume();
306d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mState = STATE_IDLE;
307d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        updateFocusUI();
308d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mHandler.removeMessages(RESET_TOUCH_FOCUS);
309d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
310d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
311d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private void capture() {
312d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        if (mListener.capture()) {
313d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            mState = STATE_IDLE;
314d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            mHandler.removeMessages(RESET_TOUCH_FOCUS);
315d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        }
316d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
317d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
318d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public void initializeToneGenerator() {
319d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        // Initialize focus tone generator.
320d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        try {
321d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            mFocusToneGenerator = new ToneGenerator(
322d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                    AudioManager.STREAM_SYSTEM, FOCUS_BEEP_VOLUME);
323d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        } catch (Throwable ex) {
324d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            Log.w(TAG, "Exception caught while creating tone generator: ", ex);
325d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            mFocusToneGenerator = null;
326d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        }
327d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
328d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
329d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public void releaseToneGenerator() {
330d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        if (mFocusToneGenerator != null) {
331d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            mFocusToneGenerator.release();
332d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            mFocusToneGenerator = null;
333d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        }
334d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
335d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
33658dadc3028b3af2e9895089e1b39ad1ab982ece2Wu-cheng Li    // This can only be called after mParameters is initialized.
337d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public String getFocusMode() {
338d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        if (mOverrideFocusMode != null) return mOverrideFocusMode;
339d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
340bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        if (mFocusAreaSupported && mFocusArea != null) {
3416bc0f740f5d7fa6eb8aa8a4ba7dd3ab4dca999d4Wu-cheng Li            // Always use autofocus in tap-to-focus.
342d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            mFocusMode = Parameters.FOCUS_MODE_AUTO;
343d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        } else {
344d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // The default is continuous autofocus.
345d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            mFocusMode = mPreferences.getString(
346d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                    CameraSettings.KEY_FOCUS_MODE, mDefaultFocusMode);
347d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        }
348d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        if (!isSupported(mFocusMode, mParameters.getSupportedFocusModes())) {
349d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // For some reasons, the driver does not support the current
350d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            // focus mode. Fall back to auto.
351d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            if (isSupported(Parameters.FOCUS_MODE_AUTO,
352d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                    mParameters.getSupportedFocusModes())) {
353d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                mFocusMode = Parameters.FOCUS_MODE_AUTO;
354d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            } else {
355d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                mFocusMode = mParameters.getFocusMode();
356d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            }
357d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        }
358d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        return mFocusMode;
359d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
360d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
361bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang    public List<Area> getFocusAreas() {
362bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        return mFocusArea;
363bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang    }
364bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang
365bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang    public List<Area> getMeteringAreas() {
366bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        return mMeteringArea;
367d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
368d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
369d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public void updateFocusUI() {
370d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        if (!mInitialized) return;
371d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
37220b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li        // Set the length of focus indicator according to preview frame size.
373d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        int len = Math.min(mPreviewFrame.getWidth(), mPreviewFrame.getHeight()) / 4;
374bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        ViewGroup.LayoutParams layout = mFocusIndicator.getLayoutParams();
375d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        layout.width = len;
376d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        layout.height = len;
377d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
37820b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li        // Show only focus indicator or face indicator.
37920b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li        boolean faceExists = (mFaceView != null && mFaceView.faceExists());
38020b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li        FocusIndicator focusIndicator = (faceExists) ? mFaceView : mFocusIndicator;
38120b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li
382d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        if (mState == STATE_IDLE) {
383bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang            if (mFocusArea == null) {
38420b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li                focusIndicator.clear();
385d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            } else {
38620b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li                // Users touch on the preview and the indicator represents the
387d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                // metering area. Either focus area is not supported or
388d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li                // autoFocus call is not required.
38920b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li                focusIndicator.showStart();
390d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            }
39120b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li        } else if (mState == STATE_FOCUSING || mState == STATE_FOCUSING_SNAP_ON_FINISH) {
39220b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li            focusIndicator.showStart();
393a7a50a45c75585e350eb730574b1e531468e8b18Wu-cheng Li        } else {
394a7a50a45c75585e350eb730574b1e531468e8b18Wu-cheng Li            // In CAF, do not show success or failure because it only returns
395a7a50a45c75585e350eb730574b1e531468e8b18Wu-cheng Li            // the focus status. It does not do a full scan. So the result is
396a7a50a45c75585e350eb730574b1e531468e8b18Wu-cheng Li            // failure most of the time.
397a7a50a45c75585e350eb730574b1e531468e8b18Wu-cheng Li            if (Parameters.FOCUS_MODE_CONTINUOUS_PICTURE.equals(mFocusMode)) {
398a7a50a45c75585e350eb730574b1e531468e8b18Wu-cheng Li                focusIndicator.showStart();
399a7a50a45c75585e350eb730574b1e531468e8b18Wu-cheng Li            } else if (mState == STATE_SUCCESS) {
400a7a50a45c75585e350eb730574b1e531468e8b18Wu-cheng Li                focusIndicator.showSuccess();
401a7a50a45c75585e350eb730574b1e531468e8b18Wu-cheng Li            } else if (mState == STATE_FAIL) {
402a7a50a45c75585e350eb730574b1e531468e8b18Wu-cheng Li                focusIndicator.showFail();
403a7a50a45c75585e350eb730574b1e531468e8b18Wu-cheng Li            }
404d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        }
405d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
406d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
407d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public void resetTouchFocus() {
408d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        if (!mInitialized) return;
409d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
41020b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li        // Put focus indicator to the center.
411d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        RelativeLayout.LayoutParams p =
41220b3c3526ebb8d8a6873f7a1110f23847a843515Wu-cheng Li                (RelativeLayout.LayoutParams) mFocusIndicatorRotateLayout.getLayoutParams();
413d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        int[] rules = p.getRules();
414d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        rules[RelativeLayout.CENTER_IN_PARENT] = RelativeLayout.TRUE;
415d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        p.setMargins(0, 0, 0, 0);
416d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
417bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        mFocusArea = null;
418bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        mMeteringArea = null;
419bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang    }
420bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang
421bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang    public void calculateTapArea(int focusWidth, int focusHeight, double areaMultiple,
422bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang            int x, int y, int previewWidth, int previewHeight, Rect rect) {
423bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        int areaWidth = (int)(focusWidth * areaMultiple);
424bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        int areaHeight = (int)(focusHeight * areaMultiple);
425bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        int areaLeft = Util.clamp(x - areaWidth / 2, 0, previewWidth - areaWidth);
426bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        int areaTop = Util.clamp(y - areaHeight / 2, 0, previewHeight - areaHeight);
427bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang        convertToFocusArea(areaLeft, areaTop, areaWidth, areaHeight, previewWidth, previewHeight,
428bd29d3c5d59b375d77334aaa426545dc781b95fdChih-yu Huang                rect);
429d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
430d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
431d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    // Convert the touch point to the focus area in driver format.
432d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public static void convertToFocusArea(int left, int top, int focusWidth, int focusHeight,
433d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li            int previewWidth, int previewHeight, Rect rect) {
434d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        rect.left = Math.round((float) left / previewWidth * 2000 - 1000);
435d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        rect.top = Math.round((float) top / previewHeight * 2000 - 1000);
436d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        rect.right = Math.round((float) (left + focusWidth) / previewWidth * 2000 - 1000);
437d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        rect.bottom = Math.round((float) (top + focusHeight) / previewHeight * 2000 - 1000);
438d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
439d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
440d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public boolean isFocusCompleted() {
441d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        return mState == STATE_SUCCESS || mState == STATE_FAIL;
442d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
443d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
444d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public void removeMessages() {
445d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mHandler.removeMessages(RESET_TOUCH_FOCUS);
446d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
447d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
448d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    public void overrideFocusMode(String focusMode) {
449d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        mOverrideFocusMode = focusMode;
450d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
451d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li
452d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    private static boolean isSupported(String value, List<String> supported) {
453d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li        return supported == null ? false : supported.indexOf(value) >= 0;
454d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li    }
455d480002ccad05cf992c628c72884091c36cc654cWu-cheng Li}
456