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