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;
241d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohdeimport com.android.camera.device.ActiveCameraDeviceTracker;
251d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohdeimport com.android.camera.device.CameraId;
2620fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kongimport com.android.camera.util.CameraUtil;
2745f316bcecb8713cbb217507981fd657fcdaa274Alan Newbergerimport com.android.camera.util.GservicesHelper;
285a344964cb003525727c31d295ca3a592c245606Sol Boucherimport com.android.ex.camera2.portability.CameraAgent;
2929a009c974f153f72cd5e28851a8cb85a691e215Alan Newbergerimport com.android.ex.camera2.portability.CameraDeviceInfo;
302a0e18e280dfe541d4740345511ad299099cda79Senpo Huimport com.android.ex.camera2.portability.CameraExceptionHandler;
3120fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong
321d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohdeimport javax.annotation.Nonnull;
331d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohdeimport javax.annotation.Nullable;
341d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohde
3520fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong/**
3620fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong * A class which implements {@link com.android.camera.app.CameraProvider} used
3720fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong * by {@link com.android.camera.CameraActivity}.
3820fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong * TODO: Make this class package private.
3920fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong */
405a344964cb003525727c31d295ca3a592c245606Sol Boucherpublic class CameraController implements CameraAgent.CameraOpenCallback, CameraProvider {
415596b4c902dcb685928b43678f428746ca5ffd08Angus Kong    private static final Log.Tag TAG = new Log.Tag("CameraController");
42432c964bb528a28600f19e18e81ff2b6407bb22dAngus Kong    private static final int EMPTY_REQUEST = -1;
43846d3abfe3da2fa2a5593c7d40a196005408bed1Sascha Haeberling    private final Context mContext;
44846d3abfe3da2fa2a5593c7d40a196005408bed1Sascha Haeberling    private final Handler mCallbackHandler;
455a344964cb003525727c31d295ca3a592c245606Sol Boucher    private final CameraAgent mCameraAgent;
4644ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher    private final CameraAgent mCameraAgentNg;
471d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohde    private final ActiveCameraDeviceTracker mActiveCameraDeviceTracker;
481d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohde
491d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohde    private CameraAgent.CameraOpenCallback mCallbackReceiver;
5044ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher
5144ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher    /** The one for the API that is currently in use (deprecated one by default). */
5244ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher    private CameraDeviceInfo mInfo;
5320fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong
545a344964cb003525727c31d295ca3a592c245606Sol Boucher    private CameraAgent.CameraProxy mCameraProxy;
55432c964bb528a28600f19e18e81ff2b6407bb22dAngus Kong    private int mRequestingCameraId = EMPTY_REQUEST;
5620fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong
5720fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    /**
5844ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher     * Determines which of mCameraAgent and mCameraAgentNg is currently in use.
5944ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher     * <p>It's only possible to enable this if the new API is actually
6044ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher     * supported.</p>
6144ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher     */
6244ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher    private boolean mUsingNewApi = false;
6344ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher
6444ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher    /**
6520fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong     * Constructor.
6620fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong     *
6720fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong     * @param context The {@link android.content.Context} used to check if the
6820fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong     *                camera is disabled.
6920fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong     * @param handler The {@link android.os.Handler} to post the camera
7020fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong     *                callbacks to.
7120fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong     * @param cameraManager Used for camera open/close.
7244ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher     * @param cameraManagerNg Used for camera open/close with the new API. If
7344ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher     *                        {@code null} or the same object as
7444ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher     *                        {@code cameraManager}, the new API will not be
7544ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher     *                        exposed and requests for it will get the old one.
761d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohde     * @param activeCameraDeviceTracker Tracks the active device across multiple
771d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohde     *                                  api versions and implementations.
7820fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong     */
791d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohde    public CameraController(@Nonnull Context context,
801d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohde          @Nullable CameraAgent.CameraOpenCallback callbackReceiver,
811d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohde          @Nonnull Handler handler,
821d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohde          @Nonnull CameraAgent cameraManager,
831d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohde          @Nonnull CameraAgent cameraManagerNg,
841d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohde          @Nonnull ActiveCameraDeviceTracker activeCameraDeviceTracker) {
8520fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong        mContext = context;
8620fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong        mCallbackReceiver = callbackReceiver;
8720fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong        mCallbackHandler = handler;
885a344964cb003525727c31d295ca3a592c245606Sol Boucher        mCameraAgent = cameraManager;
8944ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher        // If the new implementation is the same as the old, the
9044ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher        // CameraAgentFactory decided this device doesn't support the new API.
9144ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher        mCameraAgentNg = cameraManagerNg != cameraManager ? cameraManagerNg : null;
921d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohde        mActiveCameraDeviceTracker = activeCameraDeviceTracker;
935a344964cb003525727c31d295ca3a592c245606Sol Boucher        mInfo = mCameraAgent.getCameraDeviceInfo();
94c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        if (mInfo == null && mCallbackReceiver != null) {
95c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong            mCallbackReceiver.onDeviceOpenFailure(-1, "GETTING_CAMERA_INFO");
96c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        }
9720fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    }
9820fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong
9920fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    @Override
1002a0e18e280dfe541d4740345511ad299099cda79Senpo Hu    public void setCameraExceptionHandler(CameraExceptionHandler exceptionHandler) {
1012a0e18e280dfe541d4740345511ad299099cda79Senpo Hu        mCameraAgent.setCameraExceptionHandler(exceptionHandler);
10244ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher        if (mCameraAgentNg != null) {
1032a0e18e280dfe541d4740345511ad299099cda79Senpo Hu            mCameraAgentNg.setCameraExceptionHandler(exceptionHandler);
10444ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher        }
105630d55ba8111357730119899565026be503264c0Erin Dahlgren    }
106630d55ba8111357730119899565026be503264c0Erin Dahlgren
107630d55ba8111357730119899565026be503264c0Erin Dahlgren    @Override
10843e1813a5d4a59ef107768eb523d76ae2781cb02Sol Boucher    public CameraDeviceInfo.Characteristics getCharacteristics(int cameraId) {
109c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        if (mInfo == null) {
110c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong            return null;
111c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        }
11243e1813a5d4a59ef107768eb523d76ae2781cb02Sol Boucher        return mInfo.getCharacteristics(cameraId);
11320fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    }
11420fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong
11520fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    @Override
116d46ac0034a0fe7b700c4f39499dd22c2c5da5300Paul Rohde    @Deprecated
1171d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohde    public CameraId getCurrentCameraId() {
1181d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohde        return mActiveCameraDeviceTracker.getActiveOrPreviousCamera();
1196190c36db653e848f29d1caefc4fa1bb61e8a662Erin Dahlgren    }
1206190c36db653e848f29d1caefc4fa1bb61e8a662Erin Dahlgren
1216190c36db653e848f29d1caefc4fa1bb61e8a662Erin Dahlgren    @Override
12220fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    public int getNumberOfCameras() {
123c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        if (mInfo == null) {
124c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong            return 0;
125c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        }
126c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        return mInfo.getNumberOfCameras();
12720fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    }
12820fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong
12920fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    @Override
13020fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    public int getFirstBackCameraId() {
131c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        if (mInfo == null) {
132c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong            return -1;
133c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        }
134c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        return mInfo.getFirstBackCameraId();
13520fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    }
13620fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong
13720fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    @Override
13820fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    public int getFirstFrontCameraId() {
139c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        if (mInfo == null) {
140c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong            return -1;
141c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        }
142c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        return mInfo.getFirstFrontCameraId();
14320fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    }
14420fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong
14520fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    @Override
14639b460b805adaa54f310d8637868b3a5c792b2f5Angus Kong    public boolean isFrontFacingCamera(int id) {
147c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        if (mInfo == null) {
148c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong            return false;
149c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        }
15043e1813a5d4a59ef107768eb523d76ae2781cb02Sol Boucher        if (id >= mInfo.getNumberOfCameras() || mInfo.getCharacteristics(id) == null) {
15139b460b805adaa54f310d8637868b3a5c792b2f5Angus Kong            Log.e(TAG, "Camera info not available:" + id);
15239b460b805adaa54f310d8637868b3a5c792b2f5Angus Kong            return false;
15339b460b805adaa54f310d8637868b3a5c792b2f5Angus Kong        }
15443e1813a5d4a59ef107768eb523d76ae2781cb02Sol Boucher        return mInfo.getCharacteristics(id).isFacingFront();
15539b460b805adaa54f310d8637868b3a5c792b2f5Angus Kong    }
15639b460b805adaa54f310d8637868b3a5c792b2f5Angus Kong
15739b460b805adaa54f310d8637868b3a5c792b2f5Angus Kong    @Override
15839b460b805adaa54f310d8637868b3a5c792b2f5Angus Kong    public boolean isBackFacingCamera(int id) {
159c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        if (mInfo == null) {
160c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong            return false;
161c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        }
16243e1813a5d4a59ef107768eb523d76ae2781cb02Sol Boucher        if (id >= mInfo.getNumberOfCameras() || mInfo.getCharacteristics(id) == null) {
16339b460b805adaa54f310d8637868b3a5c792b2f5Angus Kong            Log.e(TAG, "Camera info not available:" + id);
16439b460b805adaa54f310d8637868b3a5c792b2f5Angus Kong            return false;
16539b460b805adaa54f310d8637868b3a5c792b2f5Angus Kong        }
16643e1813a5d4a59ef107768eb523d76ae2781cb02Sol Boucher        return mInfo.getCharacteristics(id).isFacingBack();
16739b460b805adaa54f310d8637868b3a5c792b2f5Angus Kong    }
16839b460b805adaa54f310d8637868b3a5c792b2f5Angus Kong
16939b460b805adaa54f310d8637868b3a5c792b2f5Angus Kong    @Override
1705a344964cb003525727c31d295ca3a592c245606Sol Boucher    public void onCameraOpened(CameraAgent.CameraProxy camera) {
1710b9eb5bb8d2ef409e8c88196c0c82c8ece65728bAngus Kong        Log.v(TAG, "onCameraOpened");
1720b9eb5bb8d2ef409e8c88196c0c82c8ece65728bAngus Kong        if (mRequestingCameraId != camera.getCameraId()) {
173f578829a0f9a298fd5e4fdd9081b768f25811599Angus Kong            return;
174f578829a0f9a298fd5e4fdd9081b768f25811599Angus Kong        }
1750b9eb5bb8d2ef409e8c88196c0c82c8ece65728bAngus Kong        mCameraProxy = camera;
176432c964bb528a28600f19e18e81ff2b6407bb22dAngus Kong        mRequestingCameraId = EMPTY_REQUEST;
1770fed7e62bfa0d8351b91d3531228a113637963a3Sascha Haeberling        if (mCallbackReceiver != null) {
1780fed7e62bfa0d8351b91d3531228a113637963a3Sascha Haeberling            mCallbackReceiver.onCameraOpened(camera);
1790fed7e62bfa0d8351b91d3531228a113637963a3Sascha Haeberling        }
18020fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    }
18120fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong
18220fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    @Override
18320fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    public void onCameraDisabled(int cameraId) {
1840fed7e62bfa0d8351b91d3531228a113637963a3Sascha Haeberling        if (mCallbackReceiver != null) {
1850fed7e62bfa0d8351b91d3531228a113637963a3Sascha Haeberling            mCallbackReceiver.onCameraDisabled(cameraId);
1860fed7e62bfa0d8351b91d3531228a113637963a3Sascha Haeberling        }
18720fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    }
18820fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong
18920fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    @Override
1901b9d4fb6f649262e491c0fa743229b4930a87802Angus Kong    public void onDeviceOpenFailure(int cameraId, String info) {
1910fed7e62bfa0d8351b91d3531228a113637963a3Sascha Haeberling        if (mCallbackReceiver != null) {
1921b9d4fb6f649262e491c0fa743229b4930a87802Angus Kong            mCallbackReceiver.onDeviceOpenFailure(cameraId, info);
1930fed7e62bfa0d8351b91d3531228a113637963a3Sascha Haeberling        }
19420fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    }
19520fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong
19620fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    @Override
1970b9eb5bb8d2ef409e8c88196c0c82c8ece65728bAngus Kong    public void onDeviceOpenedAlready(int cameraId, String info) {
1980fed7e62bfa0d8351b91d3531228a113637963a3Sascha Haeberling        if (mCallbackReceiver != null) {
1990b9eb5bb8d2ef409e8c88196c0c82c8ece65728bAngus Kong            mCallbackReceiver.onDeviceOpenedAlready(cameraId, info);
2000fed7e62bfa0d8351b91d3531228a113637963a3Sascha Haeberling        }
20162753ae94be2ae7c08bf24ebcf1c462975af230fAngus Kong    }
20262753ae94be2ae7c08bf24ebcf1c462975af230fAngus Kong
20362753ae94be2ae7c08bf24ebcf1c462975af230fAngus Kong    @Override
2045a344964cb003525727c31d295ca3a592c245606Sol Boucher    public void onReconnectionFailure(CameraAgent mgr, String info) {
2050fed7e62bfa0d8351b91d3531228a113637963a3Sascha Haeberling        if (mCallbackReceiver != null) {
2060b9eb5bb8d2ef409e8c88196c0c82c8ece65728bAngus Kong            mCallbackReceiver.onReconnectionFailure(mgr, info);
2070fed7e62bfa0d8351b91d3531228a113637963a3Sascha Haeberling        }
20820fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    }
20920fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong
21020fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    @Override
21120fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    public void requestCamera(int id) {
21244ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher        requestCamera(id, false);
21344ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher    }
21444ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher
21544ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher    @Override
21644ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher    public void requestCamera(int id, boolean useNewApi) {
21729a009c974f153f72cd5e28851a8cb85a691e215Alan Newberger        Log.v(TAG, "requestCamera");
218432c964bb528a28600f19e18e81ff2b6407bb22dAngus Kong        // Based on
219432c964bb528a28600f19e18e81ff2b6407bb22dAngus Kong        // (mRequestingCameraId == id, mRequestingCameraId == EMPTY_REQUEST),
220432c964bb528a28600f19e18e81ff2b6407bb22dAngus Kong        // we have (T, T), (T, F), (F, T), (F, F).
221432c964bb528a28600f19e18e81ff2b6407bb22dAngus Kong        // (T, T): implies id == EMPTY_REQUEST. We don't allow this to happen
222432c964bb528a28600f19e18e81ff2b6407bb22dAngus Kong        //         here. Return.
223432c964bb528a28600f19e18e81ff2b6407bb22dAngus Kong        // (F, F): A previous request hasn't been fulfilled yet. Return.
224432c964bb528a28600f19e18e81ff2b6407bb22dAngus Kong        // (T, F): Already requested the same camera. No-op. Return.
225432c964bb528a28600f19e18e81ff2b6407bb22dAngus Kong        // (F, T): Nothing is going on. Continue.
226432c964bb528a28600f19e18e81ff2b6407bb22dAngus Kong        if (mRequestingCameraId != EMPTY_REQUEST || mRequestingCameraId == id) {
22720fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong            return;
22820fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong        }
229c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        if (mInfo == null) {
230c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong            return;
231c44c5d93a681d98719dfffdf7223c694e1cab715Angus Kong        }
23220fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong        mRequestingCameraId = id;
2331d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohde        mActiveCameraDeviceTracker.onCameraOpening(CameraId.fromLegacyId(id));
23444ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher
23544ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher        // Only actually use the new API if it's supported on this device.
23644ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher        useNewApi = mCameraAgentNg != null && useNewApi;
23744ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher        CameraAgent cameraManager = useNewApi ? mCameraAgentNg : mCameraAgent;
23844ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher
23920fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong        if (mCameraProxy == null) {
24020fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong            // No camera yet.
2411d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohde            checkAndOpenCamera(cameraManager, id, mCallbackHandler, this);
24244ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher        } else if (mCameraProxy.getCameraId() != id || mUsingNewApi != useNewApi) {
2438f51086c8177056345de996963515c4bd3415254Sascha Haeberling            boolean syncClose = GservicesHelper.useCamera2ApiThroughPortabilityLayer(mContext
2448f51086c8177056345de996963515c4bd3415254Sascha Haeberling                    .getContentResolver());
24529a009c974f153f72cd5e28851a8cb85a691e215Alan Newberger            Log.v(TAG, "different camera already opened, closing then reopening");
24644ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher            // Already has camera opened, and is switching cameras and/or APIs.
24744ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher            if (mUsingNewApi) {
24845f316bcecb8713cbb217507981fd657fcdaa274Alan Newberger                mCameraAgentNg.closeCamera(mCameraProxy, true);
24944ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher            } else {
25045f316bcecb8713cbb217507981fd657fcdaa274Alan Newberger                // if using API2 ensure API1 usage is also synced
25145f316bcecb8713cbb217507981fd657fcdaa274Alan Newberger                mCameraAgent.closeCamera(mCameraProxy, syncClose);
25244ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher            }
2531d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohde            checkAndOpenCamera(cameraManager, id, mCallbackHandler, this);
25420fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong        } else {
25520fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong            // The same camera, just do a reconnect.
2560b9eb5bb8d2ef409e8c88196c0c82c8ece65728bAngus Kong            Log.v(TAG, "reconnecting to use the existing camera");
25720fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong            mCameraProxy.reconnect(mCallbackHandler, this);
25820fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong            mCameraProxy = null;
25920fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong        }
26044ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher
26144ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher        mUsingNewApi = useNewApi;
26244ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher        mInfo = cameraManager.getCameraDeviceInfo();
26320fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    }
26420fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong
26520fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    @Override
26697e282a3764215ac193726e0d259e55bf94369feAngus Kong    public boolean waitingForCamera() {
26797e282a3764215ac193726e0d259e55bf94369feAngus Kong        return mRequestingCameraId != EMPTY_REQUEST;
26897e282a3764215ac193726e0d259e55bf94369feAngus Kong    }
26997e282a3764215ac193726e0d259e55bf94369feAngus Kong
27097e282a3764215ac193726e0d259e55bf94369feAngus Kong    @Override
27120fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    public void releaseCamera(int id) {
272f578829a0f9a298fd5e4fdd9081b768f25811599Angus Kong        if (mCameraProxy == null) {
273432c964bb528a28600f19e18e81ff2b6407bb22dAngus Kong            if (mRequestingCameraId == EMPTY_REQUEST) {
274f578829a0f9a298fd5e4fdd9081b768f25811599Angus Kong                // Camera not requested yet.
275f578829a0f9a298fd5e4fdd9081b768f25811599Angus Kong                Log.w(TAG, "Trying to release the camera before requesting");
276f578829a0f9a298fd5e4fdd9081b768f25811599Angus Kong            }
277f578829a0f9a298fd5e4fdd9081b768f25811599Angus Kong            // Camera requested but not available yet.
278432c964bb528a28600f19e18e81ff2b6407bb22dAngus Kong            mRequestingCameraId = EMPTY_REQUEST;
279f578829a0f9a298fd5e4fdd9081b768f25811599Angus Kong            return;
280f578829a0f9a298fd5e4fdd9081b768f25811599Angus Kong        }
281662082d70ce8dc5f679a25322a00c2733f0339f2Alan Newberger        int currentId = mCameraProxy.getCameraId();
282662082d70ce8dc5f679a25322a00c2733f0339f2Alan Newberger        if (currentId != id) {
283662082d70ce8dc5f679a25322a00c2733f0339f2Alan Newberger            if (mRequestingCameraId == id) {
284662082d70ce8dc5f679a25322a00c2733f0339f2Alan Newberger                Log.w(TAG, "Releasing camera which was requested but not yet "
285662082d70ce8dc5f679a25322a00c2733f0339f2Alan Newberger                        + "opened (current:requested): " + currentId + ":" + id);
286662082d70ce8dc5f679a25322a00c2733f0339f2Alan Newberger            } else {
287662082d70ce8dc5f679a25322a00c2733f0339f2Alan Newberger                throw new IllegalStateException("Trying to release a camera neither opened"
288662082d70ce8dc5f679a25322a00c2733f0339f2Alan Newberger                        + "nor requested (current:requested:for-release): "
289662082d70ce8dc5f679a25322a00c2733f0339f2Alan Newberger                        + currentId + ":" + mRequestingCameraId + ":" + id);
290662082d70ce8dc5f679a25322a00c2733f0339f2Alan Newberger            }
29120fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong        }
2921d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohde
2931d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohde        mActiveCameraDeviceTracker.onCameraClosed(CameraId.fromLegacyId(id));
294432c964bb528a28600f19e18e81ff2b6407bb22dAngus Kong        mRequestingCameraId = EMPTY_REQUEST;
29520fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    }
29620fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong
297846d3abfe3da2fa2a5593c7d40a196005408bed1Sascha Haeberling    public void removeCallbackReceiver() {
298846d3abfe3da2fa2a5593c7d40a196005408bed1Sascha Haeberling        mCallbackReceiver = null;
299846d3abfe3da2fa2a5593c7d40a196005408bed1Sascha Haeberling    }
300846d3abfe3da2fa2a5593c7d40a196005408bed1Sascha Haeberling
30120fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    /**
30220fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong     * Closes the opened camera device.
30320fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong     * TODO: Make this method package private.
30420fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong     */
3050b9eb5bb8d2ef409e8c88196c0c82c8ece65728bAngus Kong    public void closeCamera(boolean synced) {
306dcea7639255d5bc4b17a5976bb84de1f6dba0ed1Sascha Haeberling        Log.v(TAG, "Closing camera");
30720fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong        mCameraProxy = null;
30844ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher        if (mUsingNewApi) {
30944ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher            mCameraAgentNg.closeCamera(mCameraProxy, synced);
31044ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher        } else {
31144ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher            mCameraAgent.closeCamera(mCameraProxy, synced);
31244ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher        }
313432c964bb528a28600f19e18e81ff2b6407bb22dAngus Kong        mRequestingCameraId = EMPTY_REQUEST;
31444ce4b26614f85518d548a6750c7a08908ae3596Sol Boucher        mUsingNewApi = false;
31520fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    }
31620fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong
3171d84d7107686aa428ee2eeb1a8caf0ea3e43b1dfPaul Rohde    private static void checkAndOpenCamera(CameraAgent cameraManager,
3185a344964cb003525727c31d295ca3a592c245606Sol Boucher            final int cameraId, Handler handler, final CameraAgent.CameraOpenCallback cb) {
31929a009c974f153f72cd5e28851a8cb85a691e215Alan Newberger        Log.v(TAG, "checkAndOpenCamera");
32020fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong        try {
3218be316c7a8caf962cf3fcf5e49d332fb2718319fPaul Rohde            CameraUtil.throwIfCameraDisabled();
3220b9eb5bb8d2ef409e8c88196c0c82c8ece65728bAngus Kong            cameraManager.openCamera(handler, cameraId, cb);
32320fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong        } catch (CameraDisabledException ex) {
32420fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong            handler.post(new Runnable() {
32520fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong                @Override
32620fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong                public void run() {
32720fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong                    cb.onCameraDisabled(cameraId);
32820fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong                }
32920fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong            });
33020fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong        }
33120fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong    }
3324d4a4bc8891bbfc5a7ca842f2981829ac3a716e8Doris Liu
3334d4a4bc8891bbfc5a7ca842f2981829ac3a716e8Doris Liu    public void setOneShotPreviewCallback(Handler handler,
3345a344964cb003525727c31d295ca3a592c245606Sol Boucher            CameraAgent.CameraPreviewDataCallback cb) {
3354d4a4bc8891bbfc5a7ca842f2981829ac3a716e8Doris Liu        mCameraProxy.setOneShotPreviewCallback(handler, cb);
3364d4a4bc8891bbfc5a7ca842f2981829ac3a716e8Doris Liu    }
33720fad249cbb587b8cf03e8e53bc64ff8e0bec7fdAngus Kong}
338