120fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong/*
220fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong * Copyright (C) 2013 The Android Open Source Project
320fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong *
420fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong * Licensed under the Apache License, Version 2.0 (the "License");
520fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong * you may not use this file except in compliance with the License.
620fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong * You may obtain a copy of the License at
720fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong *
820fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong *      http://www.apache.org/licenses/LICENSE-2.0
920fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong *
1020fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong * Unless required by applicable law or agreed to in writing, software
1120fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong * distributed under the License is distributed on an "AS IS" BASIS,
1220fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1320fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong * See the License for the specific language governing permissions and
1420fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong * limitations under the License.
1520fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong */
1620fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong
1720fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kongpackage com.android.camera.app;
1820fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong
1920fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kongimport android.content.Context;
2020fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kongimport android.os.Handler;
2120fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong
2220fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kongimport com.android.camera.CameraDisabledException;
235596b4c902dcb685928b43678f428746ca5ffd08Angus Kongimport com.android.camera.debug.Log;
2420fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kongimport com.android.camera.util.CameraUtil;
2545f316bcecb8713cbb217507981fd657fcdaa274Alan Newbergerimport com.android.camera.util.GservicesHelper;
265a344964cb003525727c31d295ca3a592c245606Sol Boucherimport com.android.ex.camera2.portability.CameraAgent;
275a344964cb003525727c31d295ca3a592c245606Sol Boucherimport com.android.ex.camera2.portability.CameraAgent.CameraExceptionCallback;
2829a009c974f153f72cd5e28851a8cb85a691e215Alan Newbergerimport com.android.ex.camera2.portability.CameraDeviceInfo;
2920fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong
3020fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong/**
3120fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong * A class which implements {@link com.android.camera.app.CameraProvider} used
3220fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong * by {@link com.android.camera.CameraActivity}.
3320fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong * TODO: Make this class package private.
3420fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong */
355a344964cb003525727c31d295ca3a592c245606Sol Boucherpublic class CameraController implements CameraAgent.CameraOpenCallback, CameraProvider {
365596b4c902dcb685928b43678f428746ca5ffd08Angus Kong    private static final Log.Tag TAG = new Log.Tag("CameraController");
37432c964bb528a28600f19e18e81ff2b6407bb22dAngus Kong    private static final int EMPTY_REQUEST = -1;
38846d3abfe3da2fa2a5593c7d40a196005408bed1Sascha Haeberling    private final Context mContext;
395a344964cb003525727c31d295ca3a592c245606Sol Boucher    private CameraAgent.CameraOpenCallback mCallbackReceiver;
40846d3abfe3da2fa2a5593c7d40a196005408bed1Sascha Haeberling    private final Handler mCallbackHandler;
415a344964cb003525727c31d295ca3a592c245606Sol Boucher    private final CameraAgent mCameraAgent;
4244ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher    private final CameraAgent mCameraAgentNg;
4344ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher
4444ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher    /** The one for the API that is currently in use (deprecated one by default). */
4544ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher    private CameraDeviceInfo mInfo;
4620fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong
475a344964cb003525727c31d295ca3a592c245606Sol Boucher    private CameraAgent.CameraProxy mCameraProxy;
48432c964bb528a28600f19e18e81ff2b6407bb22dAngus Kong    private int mRequestingCameraId = EMPTY_REQUEST;
4920fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong
5020fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    /**
5144ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher     * Determines which of mCameraAgent and mCameraAgentNg is currently in use.
5244ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher     * <p>It's only possible to enable this if the new API is actually
5344ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher     * supported.</p>
5444ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher     */
5544ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher    private boolean mUsingNewApi = false;
5644ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher
5744ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher    /**
5820fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong     * Constructor.
5920fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong     *
6020fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong     * @param context The {@link android.content.Context} used to check if the
6120fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong     *                camera is disabled.
6220fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong     * @param handler The {@link android.os.Handler} to post the camera
6320fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong     *                callbacks to.
6420fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong     * @param cameraManager Used for camera open/close.
6544ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher     * @param cameraManagerNg Used for camera open/close with the new API. If
6644ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher     *                        {@code null} or the same object as
6744ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher     *                        {@code cameraManager}, the new API will not be
6844ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher     *                        exposed and requests for it will get the old one.
6920fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong     */
705a344964cb003525727c31d295ca3a592c245606Sol Boucher    public CameraController(Context context, CameraAgent.CameraOpenCallback callbackReceiver,
7144ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher            Handler handler, CameraAgent cameraManager, CameraAgent cameraManagerNg) {
7220fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong        mContext = context;
7320fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong        mCallbackReceiver = callbackReceiver;
7420fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong        mCallbackHandler = handler;
755a344964cb003525727c31d295ca3a592c245606Sol Boucher        mCameraAgent = cameraManager;
7644ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher        // If the new implementation is the same as the old, the
7744ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher        // CameraAgentFactory decided this device doesn't support the new API.
7844ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher        mCameraAgentNg = cameraManagerNg != cameraManager ? cameraManagerNg : null;
795a344964cb003525727c31d295ca3a592c245606Sol Boucher        mInfo = mCameraAgent.getCameraDeviceInfo();
80c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        if (mInfo == null && mCallbackReceiver != null) {
81c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong            mCallbackReceiver.onDeviceOpenFailure(-1, "GETTING_CAMERA_INFO");
82c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        }
8320fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    }
8420fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong
8520fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    @Override
86630d55ba8111357730119899565026be503264c0Erin Dahlgren    public void setCameraDefaultExceptionCallback(CameraExceptionCallback callback,
87630d55ba8111357730119899565026be503264c0Erin Dahlgren            Handler handler) {
885a344964cb003525727c31d295ca3a592c245606Sol Boucher        mCameraAgent.setCameraDefaultExceptionCallback(callback, handler);
8944ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher        if (mCameraAgentNg != null) {
9044ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher            mCameraAgentNg.setCameraDefaultExceptionCallback(callback, handler);
9144ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher        }
92630d55ba8111357730119899565026be503264c0Erin Dahlgren    }
93630d55ba8111357730119899565026be503264c0Erin Dahlgren
94630d55ba8111357730119899565026be503264c0Erin Dahlgren    @Override
9543e1813a5d4a59ef107768eb523d76ae2781cb02Sol Boucher    public CameraDeviceInfo.Characteristics getCharacteristics(int cameraId) {
96c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        if (mInfo == null) {
97c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong            return null;
98c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        }
9943e1813a5d4a59ef107768eb523d76ae2781cb02Sol Boucher        return mInfo.getCharacteristics(cameraId);
10020fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    }
10120fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong
10220fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    @Override
1036190c36db653e848f29d1caefc4fa1bb61e8a662Erin Dahlgren    public int getCurrentCameraId() {
1046190c36db653e848f29d1caefc4fa1bb61e8a662Erin Dahlgren        if (mCameraProxy != null) {
1056190c36db653e848f29d1caefc4fa1bb61e8a662Erin Dahlgren            return mCameraProxy.getCameraId();
1066190c36db653e848f29d1caefc4fa1bb61e8a662Erin Dahlgren        } else {
107395bc17b71d13d97b3fd9f258fcf4d5748e66e5eSol Boucher            Log.v(TAG, "getCurrentCameraId without an open camera... returning requested id");
108395bc17b71d13d97b3fd9f258fcf4d5748e66e5eSol Boucher            return mRequestingCameraId;
1096190c36db653e848f29d1caefc4fa1bb61e8a662Erin Dahlgren        }
1106190c36db653e848f29d1caefc4fa1bb61e8a662Erin Dahlgren    }
1116190c36db653e848f29d1caefc4fa1bb61e8a662Erin Dahlgren
1126190c36db653e848f29d1caefc4fa1bb61e8a662Erin Dahlgren    @Override
11320fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    public int getNumberOfCameras() {
114c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        if (mInfo == null) {
115c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong            return 0;
116c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        }
117c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        return mInfo.getNumberOfCameras();
11820fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    }
11920fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong
12020fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    @Override
12120fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    public int getFirstBackCameraId() {
122c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        if (mInfo == null) {
123c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong            return -1;
124c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        }
125c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        return mInfo.getFirstBackCameraId();
12620fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    }
12720fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong
12820fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    @Override
12920fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    public int getFirstFrontCameraId() {
130c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        if (mInfo == null) {
131c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong            return -1;
132c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        }
133c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        return mInfo.getFirstFrontCameraId();
13420fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    }
13520fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong
13620fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    @Override
13739b460b805adaa54f310d8637868b3a5c792b2f5Angus Kong    public boolean isFrontFacingCamera(int id) {
138c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        if (mInfo == null) {
139c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong            return false;
140c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        }
14143e1813a5d4a59ef107768eb523d76ae2781cb02Sol Boucher        if (id >= mInfo.getNumberOfCameras() || mInfo.getCharacteristics(id) == null) {
14239b460b805adaa54f310d8637868b3a5c792b2f5Angus Kong            Log.e(TAG, "Camera info not available:" + id);
14339b460b805adaa54f310d8637868b3a5c792b2f5Angus Kong            return false;
14439b460b805adaa54f310d8637868b3a5c792b2f5Angus Kong        }
14543e1813a5d4a59ef107768eb523d76ae2781cb02Sol Boucher        return mInfo.getCharacteristics(id).isFacingFront();
14639b460b805adaa54f310d8637868b3a5c792b2f5Angus Kong    }
14739b460b805adaa54f310d8637868b3a5c792b2f5Angus Kong
14839b460b805adaa54f310d8637868b3a5c792b2f5Angus Kong    @Override
14939b460b805adaa54f310d8637868b3a5c792b2f5Angus Kong    public boolean isBackFacingCamera(int id) {
150c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        if (mInfo == null) {
151c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong            return false;
152c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        }
15343e1813a5d4a59ef107768eb523d76ae2781cb02Sol Boucher        if (id >= mInfo.getNumberOfCameras() || mInfo.getCharacteristics(id) == null) {
15439b460b805adaa54f310d8637868b3a5c792b2f5Angus Kong            Log.e(TAG, "Camera info not available:" + id);
15539b460b805adaa54f310d8637868b3a5c792b2f5Angus Kong            return false;
15639b460b805adaa54f310d8637868b3a5c792b2f5Angus Kong        }
15743e1813a5d4a59ef107768eb523d76ae2781cb02Sol Boucher        return mInfo.getCharacteristics(id).isFacingBack();
15839b460b805adaa54f310d8637868b3a5c792b2f5Angus Kong    }
15939b460b805adaa54f310d8637868b3a5c792b2f5Angus Kong
16039b460b805adaa54f310d8637868b3a5c792b2f5Angus Kong    @Override
1615a344964cb003525727c31d295ca3a592c245606Sol Boucher    public void onCameraOpened(CameraAgent.CameraProxy camera) {
1620b9eb5bb8d2ef409e8c88196c0c82c8ece65728bAngus Kong        Log.v(TAG, "onCameraOpened");
1630b9eb5bb8d2ef409e8c88196c0c82c8ece65728bAngus Kong        if (mRequestingCameraId != camera.getCameraId()) {
1640b9eb5bb8d2ef409e8c88196c0c82c8ece65728bAngus Kong            // Not requesting any camera or not waiting for this one.
165f578829a0f9a298fd5e4fdd9081b768f25811599Angus Kong            return;
166f578829a0f9a298fd5e4fdd9081b768f25811599Angus Kong        }
1670b9eb5bb8d2ef409e8c88196c0c82c8ece65728bAngus Kong        mCameraProxy = camera;
168432c964bb528a28600f19e18e81ff2b6407bb22dAngus Kong        mRequestingCameraId = EMPTY_REQUEST;
1690fed7e62bfa0d8351b91d3531228a113637963a3Sascha Haeberling        if (mCallbackReceiver != null) {
1700fed7e62bfa0d8351b91d3531228a113637963a3Sascha Haeberling            mCallbackReceiver.onCameraOpened(camera);
1710fed7e62bfa0d8351b91d3531228a113637963a3Sascha Haeberling        }
17220fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    }
17320fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong
17420fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    @Override
17520fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    public void onCameraDisabled(int cameraId) {
1760fed7e62bfa0d8351b91d3531228a113637963a3Sascha Haeberling        if (mCallbackReceiver != null) {
1770fed7e62bfa0d8351b91d3531228a113637963a3Sascha Haeberling            mCallbackReceiver.onCameraDisabled(cameraId);
1780fed7e62bfa0d8351b91d3531228a113637963a3Sascha Haeberling        }
17920fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    }
18020fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong
18120fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    @Override
1821b9d4fb6f649262e491c0fa743229b4930a87802Angus Kong    public void onDeviceOpenFailure(int cameraId, String info) {
1830fed7e62bfa0d8351b91d3531228a113637963a3Sascha Haeberling        if (mCallbackReceiver != null) {
1841b9d4fb6f649262e491c0fa743229b4930a87802Angus Kong            mCallbackReceiver.onDeviceOpenFailure(cameraId, info);
1850fed7e62bfa0d8351b91d3531228a113637963a3Sascha Haeberling        }
18620fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    }
18720fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong
18820fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    @Override
1890b9eb5bb8d2ef409e8c88196c0c82c8ece65728bAngus Kong    public void onDeviceOpenedAlready(int cameraId, String info) {
1900fed7e62bfa0d8351b91d3531228a113637963a3Sascha Haeberling        if (mCallbackReceiver != null) {
1910b9eb5bb8d2ef409e8c88196c0c82c8ece65728bAngus Kong            mCallbackReceiver.onDeviceOpenedAlready(cameraId, info);
1920fed7e62bfa0d8351b91d3531228a113637963a3Sascha Haeberling        }
19362753ae94be2ae7c08bf24ebcf1c462975af230fAngus Kong    }
19462753ae94be2ae7c08bf24ebcf1c462975af230fAngus Kong
19562753ae94be2ae7c08bf24ebcf1c462975af230fAngus Kong    @Override
1965a344964cb003525727c31d295ca3a592c245606Sol Boucher    public void onReconnectionFailure(CameraAgent mgr, String info) {
1970fed7e62bfa0d8351b91d3531228a113637963a3Sascha Haeberling        if (mCallbackReceiver != null) {
1980b9eb5bb8d2ef409e8c88196c0c82c8ece65728bAngus Kong            mCallbackReceiver.onReconnectionFailure(mgr, info);
1990fed7e62bfa0d8351b91d3531228a113637963a3Sascha Haeberling        }
20020fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    }
20120fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong
20220fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    @Override
20320fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    public void requestCamera(int id) {
20444ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher        requestCamera(id, false);
20544ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher    }
20644ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher
20744ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher    @Override
20844ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher    public void requestCamera(int id, boolean useNewApi) {
20929a009c974f153f72cd5e28851a8cb85a691e215Alan Newberger        Log.v(TAG, "requestCamera");
210432c964bb528a28600f19e18e81ff2b6407bb22dAngus Kong        // Based on
211432c964bb528a28600f19e18e81ff2b6407bb22dAngus Kong        // (mRequestingCameraId == id, mRequestingCameraId == EMPTY_REQUEST),
212432c964bb528a28600f19e18e81ff2b6407bb22dAngus Kong        // we have (T, T), (T, F), (F, T), (F, F).
213432c964bb528a28600f19e18e81ff2b6407bb22dAngus Kong        // (T, T): implies id == EMPTY_REQUEST. We don't allow this to happen
214432c964bb528a28600f19e18e81ff2b6407bb22dAngus Kong        //         here. Return.
215432c964bb528a28600f19e18e81ff2b6407bb22dAngus Kong        // (F, F): A previous request hasn't been fulfilled yet. Return.
216432c964bb528a28600f19e18e81ff2b6407bb22dAngus Kong        // (T, F): Already requested the same camera. No-op. Return.
217432c964bb528a28600f19e18e81ff2b6407bb22dAngus Kong        // (F, T): Nothing is going on. Continue.
218432c964bb528a28600f19e18e81ff2b6407bb22dAngus Kong        if (mRequestingCameraId != EMPTY_REQUEST || mRequestingCameraId == id) {
21920fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong            return;
22020fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong        }
221c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        if (mInfo == null) {
222c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong            return;
223c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        }
22420fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong        mRequestingCameraId = id;
22544ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher
22644ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher        // Only actually use the new API if it's supported on this device.
22744ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher        useNewApi = mCameraAgentNg != null && useNewApi;
22844ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher        CameraAgent cameraManager = useNewApi ? mCameraAgentNg : mCameraAgent;
22944ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher
23020fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong        if (mCameraProxy == null) {
23120fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong            // No camera yet.
23244ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher            checkAndOpenCamera(mContext, cameraManager, id, mCallbackHandler, this);
23344ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher        } else if (mCameraProxy.getCameraId() != id || mUsingNewApi != useNewApi) {
23445f316bcecb8713cbb217507981fd657fcdaa274Alan Newberger            boolean syncClose = GservicesHelper.useCamera2ApiThroughPortabilityLayer(mContext);
23529a009c974f153f72cd5e28851a8cb85a691e215Alan Newberger            Log.v(TAG, "different camera already opened, closing then reopening");
23644ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher            // Already has camera opened, and is switching cameras and/or APIs.
23744ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher            if (mUsingNewApi) {
23845f316bcecb8713cbb217507981fd657fcdaa274Alan Newberger                mCameraAgentNg.closeCamera(mCameraProxy, true);
23944ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher            } else {
24045f316bcecb8713cbb217507981fd657fcdaa274Alan Newberger                // if using API2 ensure API1 usage is also synced
24145f316bcecb8713cbb217507981fd657fcdaa274Alan Newberger                mCameraAgent.closeCamera(mCameraProxy, syncClose);
24244ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher            }
24344ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher            checkAndOpenCamera(mContext, cameraManager, id, mCallbackHandler, this);
24420fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong        } else {
24520fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong            // The same camera, just do a reconnect.
2460b9eb5bb8d2ef409e8c88196c0c82c8ece65728bAngus Kong            Log.v(TAG, "reconnecting to use the existing camera");
24720fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong            mCameraProxy.reconnect(mCallbackHandler, this);
24820fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong            mCameraProxy = null;
24920fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong        }
25044ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher
25144ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher        mUsingNewApi = useNewApi;
25244ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher        mInfo = cameraManager.getCameraDeviceInfo();
25320fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    }
25420fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong
25520fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    @Override
25697e282a3764215ac193726e0d259e55bf94369feAngus Kong    public boolean waitingForCamera() {
25797e282a3764215ac193726e0d259e55bf94369feAngus Kong        return mRequestingCameraId != EMPTY_REQUEST;
25897e282a3764215ac193726e0d259e55bf94369feAngus Kong    }
25997e282a3764215ac193726e0d259e55bf94369feAngus Kong
26097e282a3764215ac193726e0d259e55bf94369feAngus Kong    @Override
26120fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    public void releaseCamera(int id) {
262f578829a0f9a298fd5e4fdd9081b768f25811599Angus Kong        if (mCameraProxy == null) {
263432c964bb528a28600f19e18e81ff2b6407bb22dAngus Kong            if (mRequestingCameraId == EMPTY_REQUEST) {
264f578829a0f9a298fd5e4fdd9081b768f25811599Angus Kong                // Camera not requested yet.
265f578829a0f9a298fd5e4fdd9081b768f25811599Angus Kong                Log.w(TAG, "Trying to release the camera before requesting");
266f578829a0f9a298fd5e4fdd9081b768f25811599Angus Kong            }
267f578829a0f9a298fd5e4fdd9081b768f25811599Angus Kong            // Camera requested but not available yet.
268432c964bb528a28600f19e18e81ff2b6407bb22dAngus Kong            mRequestingCameraId = EMPTY_REQUEST;
269f578829a0f9a298fd5e4fdd9081b768f25811599Angus Kong            return;
270f578829a0f9a298fd5e4fdd9081b768f25811599Angus Kong        }
27120fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong        if (mCameraProxy.getCameraId() != id) {
27220fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong            throw new IllegalStateException("Trying to release an unopened camera.");
27320fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong        }
274432c964bb528a28600f19e18e81ff2b6407bb22dAngus Kong        mRequestingCameraId = EMPTY_REQUEST;
27520fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    }
27620fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong
277846d3abfe3da2fa2a5593c7d40a196005408bed1Sascha Haeberling    public void removeCallbackReceiver() {
278846d3abfe3da2fa2a5593c7d40a196005408bed1Sascha Haeberling        mCallbackReceiver = null;
279846d3abfe3da2fa2a5593c7d40a196005408bed1Sascha Haeberling    }
280846d3abfe3da2fa2a5593c7d40a196005408bed1Sascha Haeberling
28120fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    /**
28220fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong     * Closes the opened camera device.
28320fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong     * TODO: Make this method package private.
28420fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong     */
2850b9eb5bb8d2ef409e8c88196c0c82c8ece65728bAngus Kong    public void closeCamera(boolean synced) {
286dcea7639255d5bc4b17a5976bb84de1f6dba0ed1Sascha Haeberling        if (mCameraProxy == null) {
287dcea7639255d5bc4b17a5976bb84de1f6dba0ed1Sascha Haeberling            Log.v(TAG, "No camera open, not closing");
288dcea7639255d5bc4b17a5976bb84de1f6dba0ed1Sascha Haeberling            return;
289dcea7639255d5bc4b17a5976bb84de1f6dba0ed1Sascha Haeberling        }
290dcea7639255d5bc4b17a5976bb84de1f6dba0ed1Sascha Haeberling        Log.v(TAG, "Closing camera");
29120fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong        mCameraProxy = null;
29244ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher        if (mUsingNewApi) {
29344ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher            mCameraAgentNg.closeCamera(mCameraProxy, synced);
29444ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher        } else {
29544ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher            mCameraAgent.closeCamera(mCameraProxy, synced);
29644ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher        }
297432c964bb528a28600f19e18e81ff2b6407bb22dAngus Kong        mRequestingCameraId = EMPTY_REQUEST;
29844ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher        mUsingNewApi = false;
29920fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    }
30020fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong
3015a344964cb003525727c31d295ca3a592c245606Sol Boucher    private static void checkAndOpenCamera(Context context, CameraAgent cameraManager,
3025a344964cb003525727c31d295ca3a592c245606Sol Boucher            final int cameraId, Handler handler, final CameraAgent.CameraOpenCallback cb) {
30329a009c974f153f72cd5e28851a8cb85a691e215Alan Newberger        Log.v(TAG, "checkAndOpenCamera");
30420fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong        try {
30520fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong            CameraUtil.throwIfCameraDisabled(context);
3060b9eb5bb8d2ef409e8c88196c0c82c8ece65728bAngus Kong            cameraManager.openCamera(handler, cameraId, cb);
30720fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong        } catch (CameraDisabledException ex) {
30820fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong            handler.post(new Runnable() {
30920fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong                @Override
31020fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong                public void run() {
31120fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong                    cb.onCameraDisabled(cameraId);
31220fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong                }
31320fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong            });
31420fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong        }
31520fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    }
3164d4a4bc8891bbfc5a7ca842f2981829ac3a716e8Doris Liu
3174d4a4bc8891bbfc5a7ca842f2981829ac3a716e8Doris Liu    public void setOneShotPreviewCallback(Handler handler,
3185a344964cb003525727c31d295ca3a592c245606Sol Boucher            CameraAgent.CameraPreviewDataCallback cb) {
3194d4a4bc8891bbfc5a7ca842f2981829ac3a716e8Doris Liu        mCameraProxy.setOneShotPreviewCallback(handler, cb);
3204d4a4bc8891bbfc5a7ca842f2981829ac3a716e8Doris Liu    }
32120fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong}
322