1/*
2 * Copyright (C) 2014 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.one.v2.core;
18
19import android.hardware.camera2.CameraAccessException;
20import android.hardware.camera2.CameraCaptureSession;
21import android.hardware.camera2.CaptureFailure;
22import android.hardware.camera2.CaptureRequest;
23import android.hardware.camera2.CaptureResult;
24import android.hardware.camera2.TotalCaptureResult;
25import android.os.Handler;
26
27import com.android.camera.one.v2.camera2proxy.CameraCaptureSessionClosedException;
28import com.android.camera.one.v2.camera2proxy.CameraCaptureSessionProxy;
29import com.android.camera.one.v2.camera2proxy.CaptureRequestBuilderProxy;
30import com.google.common.annotations.VisibleForTesting;
31
32import java.util.ArrayList;
33import java.util.HashMap;
34import java.util.List;
35import java.util.Map;
36
37/**
38 * Like {@link android.hardware.camera2.CameraCaptureSession}, but takes
39 * {@link Request}s and dispatches to the appropriate {@link ResponseListener}
40 * on a per-request basis, instead of for every {@link CaptureRequest} submitted
41 * at the same time.
42 */
43@VisibleForTesting
44public class TagDispatchCaptureSession implements FrameServer.Session {
45    private static class CaptureCallback implements CameraCaptureSessionProxy.CaptureCallback {
46        private final Map<Object, ResponseListener> mListeners;
47
48        /**
49         * @param listeners A map from tag objects to the listener to be invoked
50         *            for events related to the request with that tag.
51         */
52        public CaptureCallback(Map<Object, ResponseListener> listeners) {
53            mListeners = new HashMap<>(listeners);
54        }
55
56        @Override
57        public void onCaptureStarted(CameraCaptureSessionProxy session, CaptureRequest request,
58                long timestamp, long frameNumber) {
59            Object tag = request.getTag();
60            mListeners.get(tag).onStarted(timestamp);
61        }
62
63        @Override
64        public void onCaptureProgressed(CameraCaptureSessionProxy session, CaptureRequest request,
65                CaptureResult partialResult) {
66            Object tag = request.getTag();
67            mListeners.get(tag).onProgressed(partialResult);
68        }
69
70        @Override
71        public void onCaptureCompleted(CameraCaptureSessionProxy session, CaptureRequest request,
72                TotalCaptureResult result) {
73            Object tag = request.getTag();
74            mListeners.get(tag).onCompleted(result);
75        }
76
77        @Override
78        public void onCaptureFailed(CameraCaptureSessionProxy session, CaptureRequest request,
79                CaptureFailure failure) {
80            Object tag = request.getTag();
81            mListeners.get(tag).onFailed(failure);
82        }
83
84        @Override
85        public void onCaptureSequenceAborted(CameraCaptureSessionProxy session, int sequenceId) {
86            for (ResponseListener listener : mListeners.values()) {
87                listener.onSequenceAborted(sequenceId);
88            }
89        }
90
91        @Override
92        public void onCaptureSequenceCompleted(CameraCaptureSessionProxy session, int sequenceId,
93                long frameNumber) {
94            for (ResponseListener listener : mListeners.values()) {
95                listener.onSequenceCompleted(sequenceId, frameNumber);
96            }
97        }
98    }
99
100    private final CameraCaptureSessionProxy mCaptureSession;
101    private final Handler mCameraHandler;
102    private long mTagCounter;
103
104    public TagDispatchCaptureSession(CameraCaptureSessionProxy captureSession, Handler
105            cameraHandler) {
106        mCaptureSession = captureSession;
107        mCameraHandler = cameraHandler;
108        mTagCounter = 0;
109    }
110
111    private Object generateTag() {
112        Object tag = Long.valueOf(mTagCounter);
113        mTagCounter++;
114        return tag;
115    }
116
117    /**
118     * Submits the given burst request to the underlying
119     * {@link CameraCaptureSessionProxy}.
120     * <p/>
121     * Note that the Tag associated with the {@link CaptureRequest} from each
122     * {@link Request} will be overwritten.
123     *
124     * @param burstRequests The list of {@link Request}s to send.
125     * @param requestType Whether the request should be sent as a repeating
126     *            request.
127     * @throws CameraAccessException See
128     *             {@link CameraCaptureSession#captureBurst} and
129     *             {@link CameraCaptureSession#setRepeatingBurst}.
130     * @throws InterruptedException if interrupted while waiting to allocate
131     *             resources necessary for each {@link Request}.
132     */
133    public void submitRequest(List<Request> burstRequests, FrameServer.RequestType requestType)
134            throws
135            CameraAccessException, InterruptedException, CameraCaptureSessionClosedException,
136            ResourceAcquisitionFailedException {
137        try {
138            Map<Object, ResponseListener> tagListenerMap = new HashMap<Object, ResponseListener>();
139            List<CaptureRequest> captureRequests = new ArrayList<>(burstRequests.size());
140
141            for (Request request : burstRequests) {
142                Object tag = generateTag();
143
144                tagListenerMap.put(tag, request.getResponseListener());
145
146                CaptureRequestBuilderProxy builder = request.allocateCaptureRequest();
147                builder.setTag(tag);
148                captureRequests.add(builder.build());
149            }
150
151            if (requestType == FrameServer.RequestType.REPEATING) {
152                mCaptureSession.setRepeatingBurst(captureRequests, new
153                        CaptureCallback(tagListenerMap), mCameraHandler);
154            } else {
155                mCaptureSession.captureBurst(captureRequests, new
156                        CaptureCallback(tagListenerMap), mCameraHandler);
157            }
158        } catch (Exception e) {
159            for (Request r : burstRequests) {
160                r.abort();
161            }
162            throw e;
163        }
164    }
165
166    public void close() {
167        // Do nothing.
168    }
169}
170