diff options
author | Jianing Wei <jianingwei@google.com> | 2014-04-10 19:51:57 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2014-04-10 19:51:57 +0000 |
commit | dcb495ff86b1322256585dbd5eda92949a1e8a4f (patch) | |
tree | c173f9ccc0066b3ed727aa1100e12996822eea6f /core/java/android/hardware/camera2 | |
parent | de5a29deaed1c527a78441189e64a40cdf3d82d3 (diff) | |
parent | d2c3a825cd15aca870af3532f4dadce94e4a6b6e (diff) | |
download | frameworks_base-dcb495ff86b1322256585dbd5eda92949a1e8a4f.zip frameworks_base-dcb495ff86b1322256585dbd5eda92949a1e8a4f.tar.gz frameworks_base-dcb495ff86b1322256585dbd5eda92949a1e8a4f.tar.bz2 |
Merge "Camera2 API: enable burst capture and repeating burst."
Diffstat (limited to 'core/java/android/hardware/camera2')
7 files changed, 444 insertions, 63 deletions
diff --git a/core/java/android/hardware/camera2/CaptureResultExtras.aidl b/core/java/android/hardware/camera2/CaptureResultExtras.aidl new file mode 100644 index 0000000..6587f02 --- /dev/null +++ b/core/java/android/hardware/camera2/CaptureResultExtras.aidl @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.camera2; + +/** @hide */ +parcelable CaptureResultExtras; diff --git a/core/java/android/hardware/camera2/CaptureResultExtras.java b/core/java/android/hardware/camera2/CaptureResultExtras.java new file mode 100644 index 0000000..e5c2c1c --- /dev/null +++ b/core/java/android/hardware/camera2/CaptureResultExtras.java @@ -0,0 +1,90 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.hardware.camera2; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * @hide + */ +public class CaptureResultExtras implements Parcelable { + private int requestId; + private int subsequenceId; + private int afTriggerId; + private int precaptureTriggerId; + private long frameNumber; + + public static final Parcelable.Creator<CaptureResultExtras> CREATOR = + new Parcelable.Creator<CaptureResultExtras>() { + @Override + public CaptureResultExtras createFromParcel(Parcel in) { + return new CaptureResultExtras(in); + } + + @Override + public CaptureResultExtras[] newArray(int size) { + return new CaptureResultExtras[size]; + } + }; + + private CaptureResultExtras(Parcel in) { + readFromParcel(in); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(requestId); + dest.writeInt(subsequenceId); + dest.writeInt(afTriggerId); + dest.writeInt(precaptureTriggerId); + dest.writeLong(frameNumber); + } + + public void readFromParcel(Parcel in) { + requestId = in.readInt(); + subsequenceId = in.readInt(); + afTriggerId = in.readInt(); + precaptureTriggerId = in.readInt(); + frameNumber = in.readLong(); + } + + public int getRequestId() { + return requestId; + } + + public int getSubsequenceId() { + return subsequenceId; + } + + public int getAfTriggerId() { + return afTriggerId; + } + + public int getPrecaptureTriggerId() { + return precaptureTriggerId; + } + + public long getFrameNumber() { + return frameNumber; + } + +} diff --git a/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl b/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl index 02a73d66..a14d38b 100644 --- a/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl +++ b/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl @@ -17,6 +17,7 @@ package android.hardware.camera2; import android.hardware.camera2.impl.CameraMetadataNative; +import android.hardware.camera2.CaptureResultExtras; /** @hide */ interface ICameraDeviceCallbacks @@ -25,8 +26,9 @@ interface ICameraDeviceCallbacks * Keep up-to-date with frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h */ - oneway void onCameraError(int errorCode); + oneway void onCameraError(int errorCode, in CaptureResultExtras resultExtras); oneway void onCameraIdle(); - oneway void onCaptureStarted(int requestId, long timestamp); - oneway void onResultReceived(int requestId, in CameraMetadataNative result); + oneway void onCaptureStarted(in CaptureResultExtras resultExtras, long timestamp); + oneway void onResultReceived(in CameraMetadataNative result, + in CaptureResultExtras resultExtras); } diff --git a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl index 1936963..d77f3d1 100644 --- a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl +++ b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl @@ -20,6 +20,8 @@ import android.view.Surface; import android.hardware.camera2.impl.CameraMetadataNative; import android.hardware.camera2.CaptureRequest; +import android.hardware.camera2.LongParcelable; + /** @hide */ interface ICameraDeviceUser { @@ -31,9 +33,13 @@ interface ICameraDeviceUser // ints here are status_t // non-negative value is the requestId. negative value is status_t - int submitRequest(in CaptureRequest request, boolean streaming); + int submitRequest(in CaptureRequest request, boolean streaming, + out LongParcelable lastFrameNumber); + + int submitRequestList(in List<CaptureRequest> requestList, boolean streaming, + out LongParcelable lastFrameNumber); - int cancelRequest(int requestId); + int cancelRequest(int requestId, out LongParcelable lastFrameNumber); int deleteStream(int streamId); @@ -46,5 +52,5 @@ interface ICameraDeviceUser int waitUntilIdle(); - int flush(); + int flush(out LongParcelable lastFrameNumber); } diff --git a/core/java/android/hardware/camera2/LongParcelable.aidl b/core/java/android/hardware/camera2/LongParcelable.aidl new file mode 100644 index 0000000..7d7e51b --- /dev/null +++ b/core/java/android/hardware/camera2/LongParcelable.aidl @@ -0,0 +1,20 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.hardware.camera2; + +/** @hide */ +parcelable LongParcelable;
\ No newline at end of file diff --git a/core/java/android/hardware/camera2/LongParcelable.java b/core/java/android/hardware/camera2/LongParcelable.java new file mode 100644 index 0000000..97b0631 --- /dev/null +++ b/core/java/android/hardware/camera2/LongParcelable.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.hardware.camera2; + +import android.os.Parcel; +import android.os.Parcelable; + +/** + * @hide + */ +public class LongParcelable implements Parcelable { + private long number; + + public LongParcelable() { + this.number = 0; + } + + public LongParcelable(long number) { + this.number = number; + } + + public static final Parcelable.Creator<LongParcelable> CREATOR = + new Parcelable.Creator<LongParcelable>() { + @Override + public LongParcelable createFromParcel(Parcel in) { + return new LongParcelable(in); + } + + @Override + public LongParcelable[] newArray(int size) { + return new LongParcelable[size]; + } + }; + + private LongParcelable(Parcel in) { + readFromParcel(in); + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeLong(number); + } + + public void readFromParcel(Parcel in) { + number = in.readLong(); + } + + public long getNumber() { + return number; + } + + public void setNumber(long number) { + this.number = number; + } + +} diff --git a/core/java/android/hardware/camera2/impl/CameraDevice.java b/core/java/android/hardware/camera2/impl/CameraDevice.java index ecc461e..cd44b51 100644 --- a/core/java/android/hardware/camera2/impl/CameraDevice.java +++ b/core/java/android/hardware/camera2/impl/CameraDevice.java @@ -21,8 +21,10 @@ import static android.hardware.camera2.CameraAccessException.CAMERA_IN_USE; import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureResult; +import android.hardware.camera2.CaptureResultExtras; import android.hardware.camera2.ICameraDeviceCallbacks; import android.hardware.camera2.ICameraDeviceUser; +import android.hardware.camera2.LongParcelable; import android.hardware.camera2.utils.CameraBinderDecorator; import android.hardware.camera2.utils.CameraRuntimeException; import android.os.Handler; @@ -33,10 +35,12 @@ import android.util.Log; import android.util.SparseArray; import android.view.Surface; +import java.util.AbstractMap.SimpleEntry; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; +import java.util.TreeSet; /** * HAL2.1+ implementation of CameraDevice. Use CameraManager#open to instantiate @@ -69,10 +73,24 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { private final String mCameraId; + /** + * A list tracking request and its expected last frame. + * Updated when calling ICameraDeviceUser methods. + */ + private final List<SimpleEntry</*frameNumber*/Long, /*requestId*/Integer>> + mFrameNumberRequestPairs = new ArrayList<SimpleEntry<Long, Integer>>(); + + /** + * An object tracking received frame numbers. + * Updated when receiving callbacks from ICameraDeviceCallbacks. + */ + private final FrameNumberTracker mFrameNumberTracker = new FrameNumberTracker(); + // Runnables for all state transitions, except error, which needs the // error code argument private final Runnable mCallOnOpened = new Runnable() { + @Override public void run() { if (!CameraDevice.this.isClosed()) { mDeviceListener.onOpened(CameraDevice.this); @@ -81,6 +99,7 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { }; private final Runnable mCallOnUnconfigured = new Runnable() { + @Override public void run() { if (!CameraDevice.this.isClosed()) { mDeviceListener.onUnconfigured(CameraDevice.this); @@ -89,6 +108,7 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { }; private final Runnable mCallOnActive = new Runnable() { + @Override public void run() { if (!CameraDevice.this.isClosed()) { mDeviceListener.onActive(CameraDevice.this); @@ -97,6 +117,7 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { }; private final Runnable mCallOnBusy = new Runnable() { + @Override public void run() { if (!CameraDevice.this.isClosed()) { mDeviceListener.onBusy(CameraDevice.this); @@ -105,12 +126,14 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { }; private final Runnable mCallOnClosed = new Runnable() { + @Override public void run() { mDeviceListener.onClosed(CameraDevice.this); } }; private final Runnable mCallOnIdle = new Runnable() { + @Override public void run() { if (!CameraDevice.this.isClosed()) { mDeviceListener.onIdle(CameraDevice.this); @@ -119,6 +142,7 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { }; private final Runnable mCallOnDisconnected = new Runnable() { + @Override public void run() { if (!CameraDevice.this.isClosed()) { mDeviceListener.onDisconnected(CameraDevice.this); @@ -249,22 +273,26 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { @Override public int capture(CaptureRequest request, CaptureListener listener, Handler handler) throws CameraAccessException { - return submitCaptureRequest(request, listener, handler, /*streaming*/false); + if (DEBUG) { + Log.d(TAG, "calling capture"); + } + List<CaptureRequest> requestList = new ArrayList<CaptureRequest>(); + requestList.add(request); + return submitCaptureRequest(requestList, listener, handler, /*streaming*/false); } @Override public int captureBurst(List<CaptureRequest> requests, CaptureListener listener, Handler handler) throws CameraAccessException { + // TODO: remove this. Throw IAE if the request is null or empty. Need to update API doc. if (requests.isEmpty()) { Log.w(TAG, "Capture burst request list is empty, do nothing!"); return -1; } - // TODO - throw new UnsupportedOperationException("Burst capture implemented yet"); - + return submitCaptureRequest(requests, listener, handler, /*streaming*/false); } - private int submitCaptureRequest(CaptureRequest request, CaptureListener listener, + private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureListener listener, Handler handler, boolean repeating) throws CameraAccessException { // Need a valid handler, or current thread needs to have a looper, if @@ -281,8 +309,13 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { stopRepeating(); } + LongParcelable lastFrameNumberRef = new LongParcelable(); try { - requestId = mRemoteDevice.submitRequest(request, repeating); + requestId = mRemoteDevice.submitRequestList(requestList, repeating, + /*out*/lastFrameNumberRef); + if (!repeating) { + Log.v(TAG, "last frame number " + lastFrameNumberRef.getNumber()); + } } catch (CameraRuntimeException e) { throw e.asChecked(); } catch (RemoteException e) { @@ -290,12 +323,29 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { return -1; } if (listener != null) { - mCaptureListenerMap.put(requestId, new CaptureListenerHolder(listener, request, - handler, repeating)); + mCaptureListenerMap.put(requestId, new CaptureListenerHolder(listener, + requestList, handler, repeating)); } + long lastFrameNumber = lastFrameNumberRef.getNumber(); + /** + * If it's the first repeating request, then returned lastFrameNumber can be + * negative. Otherwise, it should always be non-negative. + */ + if (((lastFrameNumber < 0) && (requestId > 0)) + || ((lastFrameNumber < 0) && (!repeating))) { + throw new AssertionError(String.format("returned bad frame number %d", + lastFrameNumber)); + } if (repeating) { + if (mRepeatingRequestId != REQUEST_ID_NONE) { + mFrameNumberRequestPairs.add( + new SimpleEntry<Long, Integer>(lastFrameNumber, mRepeatingRequestId)); + } mRepeatingRequestId = requestId; + } else { + mFrameNumberRequestPairs.add( + new SimpleEntry<Long, Integer>(lastFrameNumber, requestId)); } if (mIdle) { @@ -310,18 +360,20 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { @Override public int setRepeatingRequest(CaptureRequest request, CaptureListener listener, Handler handler) throws CameraAccessException { - return submitCaptureRequest(request, listener, handler, /*streaming*/true); + List<CaptureRequest> requestList = new ArrayList<CaptureRequest>(); + requestList.add(request); + return submitCaptureRequest(requestList, listener, handler, /*streaming*/true); } @Override public int setRepeatingBurst(List<CaptureRequest> requests, CaptureListener listener, Handler handler) throws CameraAccessException { + // TODO: remove this. Throw IAE if the request is null or empty. Need to update API doc. if (requests.isEmpty()) { Log.w(TAG, "Set Repeating burst request list is empty, do nothing!"); return -1; } - // TODO - throw new UnsupportedOperationException("Burst capture implemented yet"); + return submitCaptureRequest(requests, listener, handler, /*streaming*/true); } @Override @@ -340,7 +392,15 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { } try { - mRemoteDevice.cancelRequest(requestId); + LongParcelable lastFrameNumberRef = new LongParcelable(); + mRemoteDevice.cancelRequest(requestId, /*out*/lastFrameNumberRef); + long lastFrameNumber = lastFrameNumberRef.getNumber(); + if ((lastFrameNumber < 0) && (requestId > 0)) { + throw new AssertionError(String.format("returned bad frame number %d", + lastFrameNumber)); + } + mFrameNumberRequestPairs.add( + new SimpleEntry<Long, Integer>(lastFrameNumber, requestId)); } catch (CameraRuntimeException e) { throw e.asChecked(); } catch (RemoteException e) { @@ -379,7 +439,17 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { mDeviceHandler.post(mCallOnBusy); try { - mRemoteDevice.flush(); + LongParcelable lastFrameNumberRef = new LongParcelable(); + mRemoteDevice.flush(/*out*/lastFrameNumberRef); + if (mRepeatingRequestId != REQUEST_ID_NONE) { + long lastFrameNumber = lastFrameNumberRef.getNumber(); + if (lastFrameNumber < 0) { + Log.e(TAG, String.format("returned bad frame number %d", lastFrameNumber)); + } + mFrameNumberRequestPairs.add( + new SimpleEntry<Long, Integer>(lastFrameNumber, mRepeatingRequestId)); + mRepeatingRequestId = REQUEST_ID_NONE; + } } catch (CameraRuntimeException e) { throw e.asChecked(); } catch (RemoteException e) { @@ -425,18 +495,18 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { private final boolean mRepeating; private final CaptureListener mListener; - private final CaptureRequest mRequest; + private final List<CaptureRequest> mRequestList; private final Handler mHandler; - CaptureListenerHolder(CaptureListener listener, CaptureRequest request, Handler handler, - boolean repeating) { + CaptureListenerHolder(CaptureListener listener, List<CaptureRequest> requestList, + Handler handler, boolean repeating) { if (listener == null || handler == null) { throw new UnsupportedOperationException( "Must have a valid handler and a valid listener"); } mRepeating = repeating; mHandler = handler; - mRequest = request; + mRequestList = new ArrayList<CaptureRequest>(requestList); mListener = listener; } @@ -448,8 +518,24 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { return mListener; } + public CaptureRequest getRequest(int subsequenceId) { + if (subsequenceId >= mRequestList.size()) { + throw new IllegalArgumentException( + String.format( + "Requested subsequenceId %d is larger than request list size %d.", + subsequenceId, mRequestList.size())); + } else { + if (subsequenceId < 0) { + throw new IllegalArgumentException(String.format( + "Requested subsequenceId %d is negative", subsequenceId)); + } else { + return mRequestList.get(subsequenceId); + } + } + } + public CaptureRequest getRequest() { - return mRequest; + return getRequest(0); } public Handler getHandler() { @@ -458,6 +544,105 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { } + /** + * This class tracks the last frame number for submitted requests. + */ + public class FrameNumberTracker { + + private long mCompletedFrameNumber = -1; + private final TreeSet<Long> mFutureErrorSet = new TreeSet<Long>(); + + private void update() { + Iterator<Long> iter = mFutureErrorSet.iterator(); + while (iter.hasNext()) { + long errorFrameNumber = iter.next(); + if (errorFrameNumber == mCompletedFrameNumber + 1) { + mCompletedFrameNumber++; + iter.remove(); + } else { + break; + } + } + } + + /** + * This function is called every time when a result or an error is received. + * @param frameNumber: the frame number corresponding to the result or error + * @param isError: true if it is an error, false if it is not an error + */ + public void updateTracker(long frameNumber, boolean isError) { + if (isError) { + mFutureErrorSet.add(frameNumber); + } else { + /** + * HAL cannot send an OnResultReceived for frame N unless it knows for + * sure that all frames prior to N have either errored out or completed. + * So if the current frame is not an error, then all previous frames + * should have arrived. The following line checks whether this holds. + */ + if (frameNumber != mCompletedFrameNumber + 1) { + throw new AssertionError(String.format( + "result frame number %d comes out of order", + frameNumber)); + } + mCompletedFrameNumber++; + } + update(); + } + + public long getCompletedFrameNumber() { + return mCompletedFrameNumber; + } + + } + + private void checkAndFireSequenceComplete() { + long completedFrameNumber = mFrameNumberTracker.getCompletedFrameNumber(); + Iterator<SimpleEntry<Long, Integer> > iter = mFrameNumberRequestPairs.iterator(); + while (iter.hasNext()) { + final SimpleEntry<Long, Integer> frameNumberRequestPair = iter.next(); + if (frameNumberRequestPair.getKey() <= completedFrameNumber) { + + // remove request from mCaptureListenerMap + final int requestId = frameNumberRequestPair.getValue(); + final CaptureListenerHolder holder; + synchronized (mLock) { + int index = CameraDevice.this.mCaptureListenerMap.indexOfKey(requestId); + holder = (index >= 0) ? CameraDevice.this.mCaptureListenerMap.valueAt(index) + : null; + if (holder != null) { + CameraDevice.this.mCaptureListenerMap.removeAt(index); + } + } + iter.remove(); + + // Call onCaptureSequenceCompleted + if (holder != null) { + Runnable resultDispatch = new Runnable() { + @Override + public void run() { + if (!CameraDevice.this.isClosed()){ + if (DEBUG) { + Log.d(TAG, String.format( + "fire sequence complete for request %d", + requestId)); + } + + holder.getListener().onCaptureSequenceCompleted( + CameraDevice.this, + requestId, + // TODO: this is problematic, crop long to int + frameNumberRequestPair.getKey().intValue()); + } + } + }; + holder.getHandler().post(resultDispatch); + } + + } + } + } + public class CameraDeviceCallbacks extends ICameraDeviceCallbacks.Stub { // @@ -492,7 +677,7 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { } @Override - public void onCameraError(final int errorCode) { + public void onCameraError(final int errorCode, CaptureResultExtras resultExtras) { Runnable r = null; if (isClosed()) return; @@ -507,6 +692,7 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { case ERROR_CAMERA_DEVICE: case ERROR_CAMERA_SERVICE: r = new Runnable() { + @Override public void run() { if (!CameraDevice.this.isClosed()) { mDeviceListener.onError(CameraDevice.this, errorCode); @@ -517,6 +703,11 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { } CameraDevice.this.mDeviceHandler.post(r); } + + // Fire onCaptureSequenceCompleted + mFrameNumberTracker.updateTracker(resultExtras.getFrameNumber(), /*error*/true); + checkAndFireSequenceComplete(); + } @Override @@ -535,7 +726,8 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { } @Override - public void onCaptureStarted(int requestId, final long timestamp) { + public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) { + int requestId = resultExtras.getRequestId(); if (DEBUG) { Log.d(TAG, "Capture started for id " + requestId); } @@ -555,11 +747,12 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { // Dispatch capture start notice holder.getHandler().post( new Runnable() { + @Override public void run() { if (!CameraDevice.this.isClosed()) { holder.getListener().onCaptureStarted( CameraDevice.this, - holder.getRequest(), + holder.getRequest(resultExtras.getSubsequenceId()), timestamp); } } @@ -567,48 +760,18 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { } @Override - public void onResultReceived(int requestId, CameraMetadataNative result) - throws RemoteException { + public void onResultReceived(CameraMetadataNative result, + CaptureResultExtras resultExtras) throws RemoteException { + int requestId = resultExtras.getRequestId(); if (DEBUG) { Log.d(TAG, "Received result for id " + requestId); } - final CaptureListenerHolder holder; + final CaptureListenerHolder holder = + CameraDevice.this.mCaptureListenerMap.get(requestId); Boolean quirkPartial = result.get(CaptureResult.QUIRKS_PARTIAL_RESULT); boolean quirkIsPartialResult = (quirkPartial != null && quirkPartial); - synchronized (mLock) { - // TODO: move this whole map into this class to make it more testable, - // exposing the methods necessary like subscribeToRequest, unsubscribe.. - // TODO: make class static class - - holder = CameraDevice.this.mCaptureListenerMap.get(requestId); - - // Clean up listener once we no longer expect to see it. - if (holder != null && !holder.isRepeating() && !quirkIsPartialResult) { - CameraDevice.this.mCaptureListenerMap.remove(requestId); - } - - // TODO: add 'capture sequence completed' callback to the - // service, and clean up repeating requests there instead. - - // If we received a result for a repeating request and have - // prior repeating requests queued for deletion, remove those - // requests from mCaptureListenerMap. - if (holder != null && holder.isRepeating() && !quirkIsPartialResult - && mRepeatingRequestIdDeletedList.size() > 0) { - Iterator<Integer> iter = mRepeatingRequestIdDeletedList.iterator(); - while (iter.hasNext()) { - int deletedRequestId = iter.next(); - if (deletedRequestId < requestId) { - CameraDevice.this.mCaptureListenerMap.remove(deletedRequestId); - iter.remove(); - } - } - } - - } - // Check if we have a listener for this if (holder == null) { return; @@ -616,7 +779,7 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { if (isClosed()) return; - final CaptureRequest request = holder.getRequest(); + final CaptureRequest request = holder.getRequest(resultExtras.getSubsequenceId()); final CaptureResult resultAsCapture = new CaptureResult(result, request, requestId); Runnable resultDispatch = null; @@ -651,6 +814,12 @@ public class CameraDevice implements android.hardware.camera2.CameraDevice { } holder.getHandler().post(resultDispatch); + + // Fire onCaptureSequenceCompleted + if (!quirkIsPartialResult) { + mFrameNumberTracker.updateTracker(resultExtras.getFrameNumber(), /*error*/false); + checkAndFireSequenceComplete(); + } } } |