CameraController.java revision 43e1813a5d4a59ef107768eb523d76ae2781cb02
1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.camera.app;
18
19import android.content.Context;
20import android.hardware.Camera;
21import android.os.Handler;
22
23import com.android.camera.CameraDisabledException;
24import com.android.camera.debug.Log;
25import com.android.camera.util.CameraUtil;
26import com.android.ex.camera2.portability.CameraDeviceInfo;
27import com.android.ex.camera2.portability.CameraAgent;
28import com.android.ex.camera2.portability.CameraAgent.CameraExceptionCallback;
29
30/**
31 * A class which implements {@link com.android.camera.app.CameraProvider} used
32 * by {@link com.android.camera.CameraActivity}.
33 * TODO: Make this class package private.
34 */
35public class CameraController implements CameraAgent.CameraOpenCallback, CameraProvider {
36    private static final Log.Tag TAG = new Log.Tag("CameraController");
37    private static final int EMPTY_REQUEST = -1;
38    private final Context mContext;
39    private CameraAgent.CameraOpenCallback mCallbackReceiver;
40    private final Handler mCallbackHandler;
41    private final CameraAgent mCameraAgent;
42    private CameraDeviceInfo mInfo;
43
44    private CameraAgent.CameraProxy mCameraProxy;
45    private int mRequestingCameraId = EMPTY_REQUEST;
46
47    /**
48     * Constructor.
49     *
50     * @param context The {@link android.content.Context} used to check if the
51     *                camera is disabled.
52     * @param handler The {@link android.os.Handler} to post the camera
53     *                callbacks to.
54     * @param cameraManager Used for camera open/close.
55     */
56    public CameraController(Context context, CameraAgent.CameraOpenCallback callbackReceiver,
57            Handler handler, CameraAgent cameraManager) {
58        mContext = context;
59        mCallbackReceiver = callbackReceiver;
60        mCallbackHandler = handler;
61        mCameraAgent = cameraManager;
62        mInfo = mCameraAgent.getCameraDeviceInfo();
63        if (mInfo == null && mCallbackReceiver != null) {
64            mCallbackReceiver.onDeviceOpenFailure(-1, "GETTING_CAMERA_INFO");
65        }
66    }
67
68    @Override
69    public void setCameraDefaultExceptionCallback(CameraExceptionCallback callback,
70            Handler handler) {
71        mCameraAgent.setCameraDefaultExceptionCallback(callback, handler);
72    }
73
74    @Override
75    public CameraDeviceInfo.Characteristics getCharacteristics(int cameraId) {
76        if (mInfo == null) {
77            return null;
78        }
79        return mInfo.getCharacteristics(cameraId);
80    }
81
82    @Override
83    public int getCurrentCameraId() {
84        if (mCameraProxy != null) {
85            return mCameraProxy.getCameraId();
86        } else {
87            return -1;
88        }
89    }
90
91    @Override
92    public int getNumberOfCameras() {
93        if (mInfo == null) {
94            return 0;
95        }
96        return mInfo.getNumberOfCameras();
97    }
98
99    @Override
100    public int getFirstBackCameraId() {
101        if (mInfo == null) {
102            return -1;
103        }
104        return mInfo.getFirstBackCameraId();
105    }
106
107    @Override
108    public int getFirstFrontCameraId() {
109        if (mInfo == null) {
110            return -1;
111        }
112        return mInfo.getFirstFrontCameraId();
113    }
114
115    @Override
116    public boolean isFrontFacingCamera(int id) {
117        if (mInfo == null) {
118            return false;
119        }
120        if (id >= mInfo.getNumberOfCameras() || mInfo.getCharacteristics(id) == null) {
121            Log.e(TAG, "Camera info not available:" + id);
122            return false;
123        }
124        return mInfo.getCharacteristics(id).isFacingFront();
125    }
126
127    @Override
128    public boolean isBackFacingCamera(int id) {
129        if (mInfo == null) {
130            return false;
131        }
132        if (id >= mInfo.getNumberOfCameras() || mInfo.getCharacteristics(id) == null) {
133            Log.e(TAG, "Camera info not available:" + id);
134            return false;
135        }
136        return mInfo.getCharacteristics(id).isFacingBack();
137    }
138
139    @Override
140    public void onCameraOpened(CameraAgent.CameraProxy camera) {
141        Log.v(TAG, "onCameraOpened");
142        if (mRequestingCameraId != camera.getCameraId()) {
143            // Not requesting any camera or not waiting for this one.
144            return;
145        }
146        mCameraProxy = camera;
147        mRequestingCameraId = EMPTY_REQUEST;
148        if (mCallbackReceiver != null) {
149            mCallbackReceiver.onCameraOpened(camera);
150        }
151    }
152
153    @Override
154    public void onCameraDisabled(int cameraId) {
155        if (mCallbackReceiver != null) {
156            mCallbackReceiver.onCameraDisabled(cameraId);
157        }
158    }
159
160    @Override
161    public void onDeviceOpenFailure(int cameraId, String info) {
162        if (mCallbackReceiver != null) {
163            mCallbackReceiver.onDeviceOpenFailure(cameraId, info);
164        }
165    }
166
167    @Override
168    public void onDeviceOpenedAlready(int cameraId, String info) {
169        if (mCallbackReceiver != null) {
170            mCallbackReceiver.onDeviceOpenedAlready(cameraId, info);
171        }
172    }
173
174    @Override
175    public void onReconnectionFailure(CameraAgent mgr, String info) {
176        if (mCallbackReceiver != null) {
177            mCallbackReceiver.onReconnectionFailure(mgr, info);
178        }
179    }
180
181    @Override
182    public void requestCamera(int id) {
183        // Based on
184        // (mRequestingCameraId == id, mRequestingCameraId == EMPTY_REQUEST),
185        // we have (T, T), (T, F), (F, T), (F, F).
186        // (T, T): implies id == EMPTY_REQUEST. We don't allow this to happen
187        //         here. Return.
188        // (F, F): A previous request hasn't been fulfilled yet. Return.
189        // (T, F): Already requested the same camera. No-op. Return.
190        // (F, T): Nothing is going on. Continue.
191        if (mRequestingCameraId != EMPTY_REQUEST || mRequestingCameraId == id) {
192            return;
193        }
194        if (mInfo == null) {
195            return;
196        }
197        mRequestingCameraId = id;
198        if (mCameraProxy == null) {
199            // No camera yet.
200            checkAndOpenCamera(mContext, mCameraAgent, id, mCallbackHandler, this);
201        } else if (mCameraProxy.getCameraId() != id) {
202            // Already has another camera opened.
203            mCameraAgent.closeCamera(mCameraProxy, false);
204            checkAndOpenCamera(mContext, mCameraAgent, id, mCallbackHandler, this);
205        } else {
206            // The same camera, just do a reconnect.
207            Log.v(TAG, "reconnecting to use the existing camera");
208            mCameraProxy.reconnect(mCallbackHandler, this);
209            mCameraProxy = null;
210        }
211    }
212
213    @Override
214    public boolean waitingForCamera() {
215        return mRequestingCameraId != EMPTY_REQUEST;
216    }
217
218    @Override
219    public void releaseCamera(int id) {
220        if (mCameraProxy == null) {
221            if (mRequestingCameraId == EMPTY_REQUEST) {
222                // Camera not requested yet.
223                Log.w(TAG, "Trying to release the camera before requesting");
224            }
225            // Camera requested but not available yet.
226            mRequestingCameraId = EMPTY_REQUEST;
227            return;
228        }
229        if (mCameraProxy.getCameraId() != id) {
230            throw new IllegalStateException("Trying to release an unopened camera.");
231        }
232        mRequestingCameraId = EMPTY_REQUEST;
233    }
234
235    public void removeCallbackReceiver() {
236        mCallbackReceiver = null;
237    }
238
239    /**
240     * Closes the opened camera device.
241     * TODO: Make this method package private.
242     */
243    public void closeCamera(boolean synced) {
244        Log.v(TAG, "closing camera");
245        mCameraProxy = null;
246        mCameraAgent.closeCamera(mCameraProxy, synced);
247        mRequestingCameraId = EMPTY_REQUEST;
248    }
249
250    private static void checkAndOpenCamera(Context context, CameraAgent cameraManager,
251            final int cameraId, Handler handler, final CameraAgent.CameraOpenCallback cb) {
252        try {
253            CameraUtil.throwIfCameraDisabled(context);
254            cameraManager.openCamera(handler, cameraId, cb);
255        } catch (CameraDisabledException ex) {
256            handler.post(new Runnable() {
257                @Override
258                public void run() {
259                    cb.onCameraDisabled(cameraId);
260                }
261            });
262        }
263    }
264
265    public void setOneShotPreviewCallback(Handler handler,
266            CameraAgent.CameraPreviewDataCallback cb) {
267        mCameraProxy.setOneShotPreviewCallback(handler, cb);
268    }
269}
270