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 17 package com.android.camera.one.v2.core; 18 19 import java.util.ArrayList; 20 import java.util.HashSet; 21 import java.util.List; 22 import java.util.Set; 23 import java.util.concurrent.atomic.AtomicBoolean; 24 25 import android.hardware.camera2.CameraAccessException; 26 import android.hardware.camera2.CaptureRequest; 27 import android.hardware.camera2.CaptureResult; 28 import android.hardware.camera2.TotalCaptureResult; 29 import android.view.Surface; 30 31 import com.android.camera.async.BufferQueue; 32 import com.android.camera.async.ConcurrentBufferQueue; 33 import com.android.camera.async.Updatable; 34 import com.android.camera.one.v2.camera2proxy.CaptureRequestBuilderProxy; 35 import com.android.camera.one.v2.camera2proxy.CaptureResultProxy; 36 import com.android.camera.one.v2.camera2proxy.TotalCaptureResultProxy; 37 import com.android.camera.one.v2.common.TimestampResponseListener; 38 39 /** 40 * Conveniently builds {@link Request}s. 41 */ 42 public class RequestBuilder { 43 public static interface Factory { 44 /** 45 * Creates a new RequestBuilder. 46 * 47 * @param templateType See 48 * {@link android.hardware.camera2.CameraDevice#createCaptureRequest} 49 */ create(int templateType)50 public RequestBuilder create(int templateType) throws CameraAccessException; 51 } 52 53 private static class UnregisteredStreamProvider implements RequestImpl 54 .Allocation { 55 private final CaptureStream mCaptureStream; 56 private final BufferQueue<Long> mTimestampQueue; 57 private final AtomicBoolean mAllocated; 58 private final CaptureRequestBuilderProxy mBuilderProxy; 59 UnregisteredStreamProvider(CaptureStream captureStream, BufferQueue<Long> timestampQueue, CaptureRequestBuilderProxy builderProxy)60 private UnregisteredStreamProvider(CaptureStream captureStream, 61 BufferQueue<Long> timestampQueue, 62 CaptureRequestBuilderProxy builderProxy) { 63 mCaptureStream = captureStream; 64 mTimestampQueue = timestampQueue; 65 mAllocated = new AtomicBoolean(false); 66 mBuilderProxy = builderProxy; 67 } 68 allocate()69 public void allocate() throws InterruptedException, ResourceAcquisitionFailedException { 70 mBuilderProxy.addTarget(mCaptureStream.bind(mTimestampQueue)); 71 } 72 73 @Override abort()74 public void abort() { 75 mTimestampQueue.close(); 76 } 77 } 78 79 private static class RequestImpl implements Request { 80 private static interface Allocation { allocate()81 public void allocate() throws InterruptedException, 82 ResourceAcquisitionFailedException; 83 abort()84 public void abort(); 85 } 86 87 private final CaptureRequestBuilderProxy mCaptureRequestBuilder; 88 private final List<Allocation> mAllocations; 89 private final ResponseListener mResponseListener; 90 RequestImpl(CaptureRequestBuilderProxy builder, List<Allocation> allocations, ResponseListener responseListener)91 public RequestImpl(CaptureRequestBuilderProxy builder, List<Allocation> allocations, 92 ResponseListener responseListener) { 93 mCaptureRequestBuilder = builder; 94 mAllocations = allocations; 95 mResponseListener = responseListener; 96 } 97 98 @Override allocateCaptureRequest()99 public CaptureRequestBuilderProxy allocateCaptureRequest() throws InterruptedException, 100 ResourceAcquisitionFailedException { 101 for (Allocation allocation : mAllocations) { 102 allocation.allocate(); 103 } 104 return mCaptureRequestBuilder; 105 } 106 107 @Override getResponseListener()108 public ResponseListener getResponseListener() { 109 return mResponseListener; 110 } 111 112 @Override abort()113 public void abort() { 114 for (Allocation allocation : mAllocations) { 115 allocation.abort(); 116 } 117 } 118 } 119 120 private final CaptureRequestBuilderProxy mBuilder; 121 122 private final List<RequestImpl.Allocation> mAllocations; 123 124 /** 125 * The set of ResponseListeners to dispatch to for all updates. 126 */ 127 private final Set<ResponseListener> mResponseListeners; 128 129 /** 130 * @param builder The capture request builder to use. 131 */ RequestBuilder(CaptureRequestBuilderProxy builder)132 public RequestBuilder(CaptureRequestBuilderProxy builder) { 133 mBuilder = builder; 134 mAllocations = new ArrayList<>(); 135 mResponseListeners = new HashSet<>(); 136 } 137 138 /** 139 * Adds the given response listener. Duplicate listeners are only added 140 * once. 141 * 142 * @See {@link ResponseListeners} 143 * 144 * @param listener the listener to add. 145 */ addResponseListener(ResponseListener listener)146 public void addResponseListener(ResponseListener listener) { 147 mResponseListeners.add(listener); 148 } 149 150 /** 151 * Sets the given key-value pair. 152 * 153 * @see {@link CaptureRequest.Builder#set}. 154 */ setParam(CaptureRequest.Key<T> key, T value)155 public <T> void setParam(CaptureRequest.Key<T> key, T value) { 156 mBuilder.set(key, value); 157 } 158 159 /** 160 * Adds the given {@link CaptureStream} as an output target. Note that the 161 * {@link Surface} associated with the given {@link CaptureStream} should be 162 * one of of the surfaces added to the 163 * {@link android.hardware.camera2.CameraCaptureSession} which the built 164 * {@link Request} will be sent to. 165 * 166 * @param captureStream 167 */ addStream(CaptureStream captureStream)168 public void addStream(CaptureStream captureStream) { 169 ConcurrentBufferQueue<Long> timestamps = new ConcurrentBufferQueue<>(); 170 171 mAllocations.add(new UnregisteredStreamProvider(captureStream, 172 timestamps, mBuilder)); 173 174 mResponseListeners.add(ResponseListeners.forTimestamps(timestamps)); 175 } 176 177 /** 178 * Builds a new {@link Request} based on the current state of the builder. 179 * The builder should not be reused after this is called. 180 * 181 * @return A new {@link Request} based on the current state of the builder. 182 */ build()183 public Request build() { 184 return new RequestImpl(mBuilder, mAllocations, 185 new ResponseListenerBroadcaster(new ArrayList<>(mResponseListeners))); 186 } 187 188 } 189