LegacyCameraDevice.java revision 83159151f618c79040a2e800de8cc78f22bf760b
1feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk/*
2feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * Copyright (C) 2014 The Android Open Source Project
3feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk *
4feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * Licensed under the Apache License, Version 2.0 (the "License");
5feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * you may not use this file except in compliance with the License.
6feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * You may obtain a copy of the License at
7feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk *
8feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk *      http://www.apache.org/licenses/LICENSE-2.0
9feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk *
10feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * Unless required by applicable law or agreed to in writing, software
11feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * distributed under the License is distributed on an "AS IS" BASIS,
12feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * See the License for the specific language governing permissions and
14feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * limitations under the License.
15feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk */
16feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
17feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkpackage android.hardware.camera2.legacy;
18feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
19feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.graphics.ImageFormat;
2028c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunkimport android.graphics.SurfaceTexture;
21feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.hardware.Camera;
22df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkinimport android.hardware.camera2.CameraCharacteristics;
23feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.hardware.camera2.CaptureRequest;
24feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.hardware.camera2.impl.CaptureResultExtras;
25feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.hardware.camera2.ICameraDeviceCallbacks;
26feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.hardware.camera2.utils.LongParcelable;
27feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.hardware.camera2.impl.CameraMetadataNative;
28feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.hardware.camera2.utils.CameraRuntimeException;
29feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.os.ConditionVariable;
30feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.os.Handler;
31feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.os.HandlerThread;
32feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.os.RemoteException;
33feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.util.Log;
34a296fece2b974a11bc624fd67b275863f17df867Igor Murashkinimport android.util.Size;
35feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport android.view.Surface;
36feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
37feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport java.util.ArrayList;
383c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunkimport java.util.Collection;
39feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkimport java.util.List;
4049b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin
41ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunkimport static android.hardware.camera2.legacy.LegacyExceptionUtils.*;
4249b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkinimport static android.hardware.camera2.utils.CameraBinderDecorator.*;
43a296fece2b974a11bc624fd67b275863f17df867Igor Murashkinimport static com.android.internal.util.Preconditions.*;
44feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
45feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk/**
46feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * This class emulates the functionality of a Camera2 device using a the old Camera class.
47feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk *
48feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * <p>
49feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * There are two main components that are used to implement this:
50feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * - A state machine containing valid Camera2 device states ({@link CameraDeviceState}).
51feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * - A message-queue based pipeline that manages an old Camera class, and executes capture and
52feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk *   configuration requests.
53feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk * </p>
54feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk */
55feb50af361e4305a25758966b6b5df2738c00259Ruben Brunkpublic class LegacyCameraDevice implements AutoCloseable {
56feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    public static final String DEBUG_PROP = "HAL1ShimLogging";
57feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private final String TAG;
58feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
593e4fed203fe7c945c53c6d6bb9f160932a1d15b3Ruben Brunk    private static final boolean DEBUG = false;
60feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private final int mCameraId;
61feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private final ICameraDeviceCallbacks mDeviceCallbacks;
62feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private final CameraDeviceState mDeviceState = new CameraDeviceState();
6349b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin    private List<Surface> mConfiguredSurfaces;
64feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
65feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private final ConditionVariable mIdle = new ConditionVariable(/*open*/true);
66feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
67d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk    private final HandlerThread mResultThread = new HandlerThread("ResultThread");
68d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk    private final HandlerThread mCallbackHandlerThread = new HandlerThread("CallbackThread");
69feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private final Handler mCallbackHandler;
70d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk    private final Handler mResultHandler;
71feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private static final int ILLEGAL_VALUE = -1;
72feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
73feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private CaptureResultExtras getExtrasFromRequest(RequestHolder holder) {
74feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        if (holder == null) {
75feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            return new CaptureResultExtras(ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE,
7683159151f618c79040a2e800de8cc78f22bf760bZhijun He                    ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE);
77feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
78feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        return new CaptureResultExtras(holder.getRequestId(), holder.getSubsequeceId(),
7983159151f618c79040a2e800de8cc78f22bf760bZhijun He                /*afTriggerId*/0, /*precaptureTriggerId*/0, holder.getFrameNumber(),
8083159151f618c79040a2e800de8cc78f22bf760bZhijun He                /*partialResultCount*/1);
81feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
82feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
83feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
84feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Listener for the camera device state machine.  Calls the appropriate
85feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * {@link ICameraDeviceCallbacks} for each state transition.
86feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
87feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private final CameraDeviceState.CameraDeviceStateListener mStateListener =
88feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            new CameraDeviceState.CameraDeviceStateListener() {
89feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        @Override
90feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        public void onError(final int errorCode, RequestHolder holder) {
91feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            mIdle.open();
92feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            final CaptureResultExtras extras = getExtrasFromRequest(holder);
93d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk            mResultHandler.post(new Runnable() {
94d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                @Override
95d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                public void run() {
963e4fed203fe7c945c53c6d6bb9f160932a1d15b3Ruben Brunk                    if (DEBUG) {
973e4fed203fe7c945c53c6d6bb9f160932a1d15b3Ruben Brunk                        Log.d(TAG, "doing onError callback.");
983e4fed203fe7c945c53c6d6bb9f160932a1d15b3Ruben Brunk                    }
99d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                    try {
100d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                        mDeviceCallbacks.onCameraError(errorCode, extras);
101d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                    } catch (RemoteException e) {
102d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                        throw new IllegalStateException(
103d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                                "Received remote exception during onCameraError callback: ", e);
104d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                    }
105d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                }
106d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk            });
107feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
108feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
109feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        @Override
110feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        public void onConfiguring() {
111feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            // Do nothing
1123e4fed203fe7c945c53c6d6bb9f160932a1d15b3Ruben Brunk            if (DEBUG) {
1133e4fed203fe7c945c53c6d6bb9f160932a1d15b3Ruben Brunk                Log.d(TAG, "doing onConfiguring callback.");
1143e4fed203fe7c945c53c6d6bb9f160932a1d15b3Ruben Brunk            }
115feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
116feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
117feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        @Override
118feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        public void onIdle() {
119feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            mIdle.open();
120feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
121d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk            mResultHandler.post(new Runnable() {
122d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                @Override
123d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                public void run() {
1243e4fed203fe7c945c53c6d6bb9f160932a1d15b3Ruben Brunk                    if (DEBUG) {
1253e4fed203fe7c945c53c6d6bb9f160932a1d15b3Ruben Brunk                        Log.d(TAG, "doing onIdle callback.");
1263e4fed203fe7c945c53c6d6bb9f160932a1d15b3Ruben Brunk                    }
127d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                    try {
128d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                        mDeviceCallbacks.onCameraIdle();
129d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                    } catch (RemoteException e) {
130d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                        throw new IllegalStateException(
131d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                                "Received remote exception during onCameraIdle callback: ", e);
132d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                    }
133d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                }
134d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk            });
135feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
136feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
137feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        @Override
138feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        public void onCaptureStarted(RequestHolder holder) {
139feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            final CaptureResultExtras extras = getExtrasFromRequest(holder);
140feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
141d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk            final long timestamp = System.nanoTime();
142d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk            mResultHandler.post(new Runnable() {
143d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                @Override
144d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                public void run() {
1453e4fed203fe7c945c53c6d6bb9f160932a1d15b3Ruben Brunk                    if (DEBUG) {
1463e4fed203fe7c945c53c6d6bb9f160932a1d15b3Ruben Brunk                        Log.d(TAG, "doing onCaptureStarted callback.");
1473e4fed203fe7c945c53c6d6bb9f160932a1d15b3Ruben Brunk                    }
148d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                    try {
149d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                        // TODO: Don't fake timestamp
150d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                        mDeviceCallbacks.onCaptureStarted(extras, timestamp);
151d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                    } catch (RemoteException e) {
152d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                        throw new IllegalStateException(
153d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                                "Received remote exception during onCameraError callback: ", e);
154d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                    }
155d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                }
156d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk            });
157feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
158feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
159feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        @Override
160d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk        public void onCaptureResult(final CameraMetadataNative result, RequestHolder holder) {
161feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            final CaptureResultExtras extras = getExtrasFromRequest(holder);
162feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
163d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk            mResultHandler.post(new Runnable() {
164d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                @Override
165d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                public void run() {
1663e4fed203fe7c945c53c6d6bb9f160932a1d15b3Ruben Brunk                    if (DEBUG) {
1673e4fed203fe7c945c53c6d6bb9f160932a1d15b3Ruben Brunk                        Log.d(TAG, "doing onCaptureResult callback.");
1683e4fed203fe7c945c53c6d6bb9f160932a1d15b3Ruben Brunk                    }
169d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                    try {
170d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                        // TODO: Don't fake metadata
171d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                        mDeviceCallbacks.onResultReceived(result, extras);
172d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                    } catch (RemoteException e) {
173d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                        throw new IllegalStateException(
174d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                                "Received remote exception during onCameraError callback: ", e);
175d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                    }
176d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                }
177d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk            });
178feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
179feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    };
180feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
181feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    private final RequestThreadManager mRequestThreadManager;
182feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
183feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
18491b9aabc9fa0c058ecc4a8b3f486540c28fe1cc0Ruben Brunk     * Check if a given surface uses {@link ImageFormat#YUV_420_888} or format that can be readily
18591b9aabc9fa0c058ecc4a8b3f486540c28fe1cc0Ruben Brunk     * converted to this; YV12 and NV21 are the two currently supported formats.
186feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *
187feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @param s the surface to check.
18891b9aabc9fa0c058ecc4a8b3f486540c28fe1cc0Ruben Brunk     * @return {@code true} if the surfaces uses {@link ImageFormat#YUV_420_888} or a compatible
18991b9aabc9fa0c058ecc4a8b3f486540c28fe1cc0Ruben Brunk     *          format.
190feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
191ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    static boolean needsConversion(Surface s) throws BufferQueueAbandonedException {
192ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        int nativeType = detectSurfaceType(s);
19391b9aabc9fa0c058ecc4a8b3f486540c28fe1cc0Ruben Brunk        return nativeType == ImageFormat.YUV_420_888 || nativeType == ImageFormat.YV12 ||
19491b9aabc9fa0c058ecc4a8b3f486540c28fe1cc0Ruben Brunk                nativeType == ImageFormat.NV21;
195feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
196feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
197feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
198feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Create a new emulated camera device from a given Camera 1 API camera.
199feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *
200feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * <p>
201feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * The {@link Camera} provided to this constructor must already have been successfully opened,
202feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * and ownership of the provided camera is passed to this object.  No further calls to the
203feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * camera methods should be made following this constructor.
204feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * </p>
205feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *
206feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @param cameraId the id of the camera.
207feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @param camera an open {@link Camera} device.
208df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin     * @param characteristics the static camera characteristics for this camera device
209feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @param callbacks {@link ICameraDeviceCallbacks} callbacks to call for Camera2 API operations.
210feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
211df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin    public LegacyCameraDevice(int cameraId, Camera camera, CameraCharacteristics characteristics,
212df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin            ICameraDeviceCallbacks callbacks) {
213feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mCameraId = cameraId;
214feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mDeviceCallbacks = callbacks;
215feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        TAG = String.format("CameraDevice-%d-LE", mCameraId);
216feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
217d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk        mResultThread.start();
218d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk        mResultHandler = new Handler(mResultThread.getLooper());
219feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mCallbackHandlerThread.start();
220feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mCallbackHandler = new Handler(mCallbackHandlerThread.getLooper());
221feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mDeviceState.setCameraDeviceCallbacks(mCallbackHandler, mStateListener);
222feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mRequestThreadManager =
223df6242e374b81e802a38cb891477f05d3e4b3cbcIgor Murashkin                new RequestThreadManager(cameraId, camera, characteristics, mDeviceState);
224feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mRequestThreadManager.start();
225feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
226feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
227feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
228feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Configure the device with a set of output surfaces.
229feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *
23049b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin     * <p>Using empty or {@code null} {@code outputs} is the same as unconfiguring.</p>
23149b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin     *
23249b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin     * <p>Every surface in {@code outputs} must be non-{@code null}.</p>
23349b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin     *
234feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @param outputs a list of surfaces to set.
23549b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin     * @return an error code for this binder operation, or {@link NO_ERROR}
236feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *          on success.
237feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
238feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    public int configureOutputs(List<Surface> outputs) {
23949b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin        if (outputs != null) {
24049b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin            for (Surface output : outputs) {
24149b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                if (output == null) {
24249b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                    Log.e(TAG, "configureOutputs - null outputs are not allowed");
24349b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                    return BAD_VALUE;
24449b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                }
24549b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin            }
24649b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin        }
24749b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin
248feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        int error = mDeviceState.setConfiguring();
24949b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin        if (error == NO_ERROR) {
250feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            mRequestThreadManager.configure(outputs);
251feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            error = mDeviceState.setIdle();
252feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
25349b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin
25449b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin        // TODO: May also want to check the surfaces more deeply (e.g. state, formats, sizes..)
25549b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin        if (error == NO_ERROR) {
25649b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin            mConfiguredSurfaces = outputs != null ? new ArrayList<>(outputs) : null;
25749b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin        }
25849b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin
259feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        return error;
260feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
261feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
262feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
263feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Submit a burst of capture requests.
264feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *
265feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @param requestList a list of capture requests to execute.
266feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @param repeating {@code true} if this burst is repeating.
267feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @param frameNumber an output argument that contains either the frame number of the last frame
268feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *                    that will be returned for this request, or the frame number of the last
269feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *                    frame that will be returned for the current repeating request if this
270feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *                    burst is set to be repeating.
271feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @return the request id.
272feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
273feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    public int submitRequestList(List<CaptureRequest> requestList, boolean repeating,
274feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            /*out*/LongParcelable frameNumber) {
27549b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin        if (requestList == null || requestList.isEmpty()) {
27649b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin            Log.e(TAG, "submitRequestList - Empty/null requests are not allowed");
27749b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin            return BAD_VALUE;
27849b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin        }
27949b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin
2803c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk        List<Long> surfaceIds = (mConfiguredSurfaces == null) ? new ArrayList<Long>() :
2813c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk                getSurfaceIds(mConfiguredSurfaces);
2823c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk
28349b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin        // Make sure that there all requests have at least 1 surface; all surfaces are non-null
28449b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin        for (CaptureRequest request : requestList) {
28549b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin            if (request.getTargets().isEmpty()) {
28649b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                Log.e(TAG, "submitRequestList - "
28749b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                        + "Each request must have at least one Surface target");
28849b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                return BAD_VALUE;
28949b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin            }
29049b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin
29149b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin            for (Surface surface : request.getTargets()) {
29249b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                if (surface == null) {
29349b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                    Log.e(TAG, "submitRequestList - Null Surface targets are not allowed");
29449b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                    return BAD_VALUE;
29549b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                } else if (mConfiguredSurfaces == null) {
29649b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                    Log.e(TAG, "submitRequestList - must configure " +
29749b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                            " device with valid surfaces before submitting requests");
29849b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                    return INVALID_OPERATION;
2993c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk                } else if (!containsSurfaceId(surface, surfaceIds)) {
30049b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                    Log.e(TAG, "submitRequestList - cannot use a surface that wasn't configured");
30149b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                    return BAD_VALUE;
30249b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin                }
30349b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin            }
30449b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin        }
30549b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin
30649b2b135105e5ca5dc9547f4c6de473bebad647dIgor Murashkin        // TODO: further validation of request here
307feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mIdle.close();
308feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        return mRequestThreadManager.submitCaptureRequests(requestList, repeating,
309feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                frameNumber);
310feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
311feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
312feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
313feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Submit a single capture request.
314feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *
315feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @param request the capture request to execute.
316feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @param repeating {@code true} if this request is repeating.
317feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @param frameNumber an output argument that contains either the frame number of the last frame
318feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *                    that will be returned for this request, or the frame number of the last
319feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *                    frame that will be returned for the current repeating request if this
320feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *                    request is set to be repeating.
321feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @return the request id.
322feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
323feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    public int submitRequest(CaptureRequest request, boolean repeating,
324feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            /*out*/LongParcelable frameNumber) {
325feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        ArrayList<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
326feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        requestList.add(request);
327feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        return submitRequestList(requestList, repeating, frameNumber);
328feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
329feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
330feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
331feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Cancel the repeating request with the given request id.
332feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *
333feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @param requestId the request id of the request to cancel.
334feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * @return the last frame number to be returned from the HAL for the given repeating request, or
335feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     *          {@code INVALID_FRAME} if none exists.
336feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
337feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    public long cancelRequest(int requestId) {
338feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        return mRequestThreadManager.cancelRepeating(requestId);
339feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
340feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
341feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    /**
342feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     * Block until the {@link ICameraDeviceCallbacks#onCameraIdle()} callback is received.
343feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk     */
344feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    public void waitUntilIdle()  {
345feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mIdle.block();
346feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
347feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
348feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    @Override
349feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    public void close() {
350feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mRequestThreadManager.quit();
351feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        mCallbackHandlerThread.quitSafely();
352d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk        mResultThread.quitSafely();
353d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk
354d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk        try {
355d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk            mCallbackHandlerThread.join();
356d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk        } catch (InterruptedException e) {
357d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk            Log.e(TAG, String.format("Thread %s (%d) interrupted while quitting.",
358d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                    mCallbackHandlerThread.getName(), mCallbackHandlerThread.getId()));
359d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk        }
360d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk
361d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk        try {
362d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk            mResultThread.join();
363d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk        } catch (InterruptedException e) {
364d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk            Log.e(TAG, String.format("Thread %s (%d) interrupted while quitting.",
365d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk                    mResultThread.getName(), mResultThread.getId()));
366d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk        }
367d85e1a6ced452c9bd0d805f6ce19f50c9ea9b0a6Ruben Brunk
368feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        // TODO: throw IllegalStateException in every method after close has been called
369feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
370feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
371feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    @Override
372feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    protected void finalize() throws Throwable {
373feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        try {
374feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            close();
375feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        } catch (CameraRuntimeException e) {
376feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            Log.e(TAG, "Got error while trying to finalize, ignoring: " + e.getMessage());
377feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        } finally {
378feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk            super.finalize();
379feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk        }
380feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk    }
381feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
382a296fece2b974a11bc624fd67b275863f17df867Igor Murashkin    /**
383a296fece2b974a11bc624fd67b275863f17df867Igor Murashkin     * Query the surface for its currently configured default buffer size.
384a296fece2b974a11bc624fd67b275863f17df867Igor Murashkin     * @param surface a non-{@code null} {@code Surface}
385a296fece2b974a11bc624fd67b275863f17df867Igor Murashkin     * @return the width and height of the surface
386a296fece2b974a11bc624fd67b275863f17df867Igor Murashkin     *
387a296fece2b974a11bc624fd67b275863f17df867Igor Murashkin     * @throws NullPointerException if the {@code surface} was {@code null}
388a296fece2b974a11bc624fd67b275863f17df867Igor Murashkin     * @throws IllegalStateException if the {@code surface} was invalid
389a296fece2b974a11bc624fd67b275863f17df867Igor Murashkin     */
390ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    static Size getSurfaceSize(Surface surface) throws BufferQueueAbandonedException {
391a296fece2b974a11bc624fd67b275863f17df867Igor Murashkin        checkNotNull(surface);
392a296fece2b974a11bc624fd67b275863f17df867Igor Murashkin
393a296fece2b974a11bc624fd67b275863f17df867Igor Murashkin        int[] dimens = new int[2];
394ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        LegacyExceptionUtils.throwOnError(nativeDetectSurfaceDimens(surface, /*out*/dimens));
395a296fece2b974a11bc624fd67b275863f17df867Igor Murashkin
396a296fece2b974a11bc624fd67b275863f17df867Igor Murashkin        return new Size(dimens[0], dimens[1]);
397a296fece2b974a11bc624fd67b275863f17df867Igor Murashkin    }
398a296fece2b974a11bc624fd67b275863f17df867Igor Murashkin
399ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    static int detectSurfaceType(Surface surface) throws BufferQueueAbandonedException {
400ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        checkNotNull(surface);
401ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        return LegacyExceptionUtils.throwOnError(nativeDetectSurfaceType(surface));
402ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    }
403ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk
404ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    static void configureSurface(Surface surface, int width, int height,
405ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                                 int pixelFormat) throws BufferQueueAbandonedException {
406ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        checkNotNull(surface);
407ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        checkArgumentPositive(width, "width must be positive.");
408ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        checkArgumentPositive(height, "height must be positive.");
409ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk
410ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        LegacyExceptionUtils.throwOnError(nativeConfigureSurface(surface, width, height,
411ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                pixelFormat));
412ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    }
413ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk
414ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    static void produceFrame(Surface surface, byte[] pixelBuffer, int width,
415ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                             int height, int pixelFormat)
416ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk            throws BufferQueueAbandonedException {
417ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        checkNotNull(surface);
418ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        checkNotNull(pixelBuffer);
419ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        checkArgumentPositive(width, "width must be positive.");
420ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        checkArgumentPositive(height, "height must be positive.");
421ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk
422ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        LegacyExceptionUtils.throwOnError(nativeProduceFrame(surface, pixelBuffer, width, height,
423ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk                pixelFormat));
424ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    }
425ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk
426ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    static void setSurfaceFormat(Surface surface, int pixelFormat)
427ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk            throws BufferQueueAbandonedException {
428ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        checkNotNull(surface);
429ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk
430ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        LegacyExceptionUtils.throwOnError(nativeSetSurfaceFormat(surface, pixelFormat));
431ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    }
432ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk
433ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    static void setSurfaceDimens(Surface surface, int width, int height)
434ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk            throws BufferQueueAbandonedException {
435ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        checkNotNull(surface);
436ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        checkArgumentPositive(width, "width must be positive.");
437ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        checkArgumentPositive(height, "height must be positive.");
438ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk
439ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk        LegacyExceptionUtils.throwOnError(nativeSetSurfaceDimens(surface, width, height));
440ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    }
441ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk
4423c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk    static long getSurfaceId(Surface surface) {
4433c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk        checkNotNull(surface);
4443c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk        return nativeGetSurfaceId(surface);
4453c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk    }
4463c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk
4473c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk    static List<Long> getSurfaceIds(Collection<Surface> surfaces) {
4483c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk        if (surfaces == null) {
4493c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk            throw new NullPointerException("Null argument surfaces");
4503c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk        }
4513c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk        List<Long> surfaceIds = new ArrayList<>();
4523c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk        for (Surface s : surfaces) {
4533c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk            long id = getSurfaceId(s);
4543c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk            if (id == 0) {
4553c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk                throw new IllegalStateException(
4563c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk                        "Configured surface had null native GraphicBufferProducer pointer!");
4573c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk            }
4583c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk            surfaceIds.add(id);
4593c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk        }
4603c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk        return surfaceIds;
4613c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk    }
4623c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk
4633c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk    static boolean containsSurfaceId(Surface s, List<Long> ids) {
4643c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk        long id = getSurfaceId(s);
4653c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk        return ids.contains(id);
4663c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk    }
4673c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk
46828c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk    static void setSurfaceOrientation(Surface surface, int facing, int sensorOrientation)
46928c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk            throws BufferQueueAbandonedException {
47028c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk        checkNotNull(surface);
47128c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk        LegacyExceptionUtils.throwOnError(nativeSetSurfaceOrientation(surface, facing,
47228c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk                sensorOrientation));
47328c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk    }
47428c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk
47528c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk    static Size getTextureSize(SurfaceTexture surfaceTexture)
47628c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk            throws BufferQueueAbandonedException {
47728c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk        checkNotNull(surfaceTexture);
47828c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk
47928c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk        int[] dimens = new int[2];
48028c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk        LegacyExceptionUtils.throwOnError(nativeDetectTextureDimens(surfaceTexture,
48128c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk                /*out*/dimens));
48228c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk
48328c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk        return new Size(dimens[0], dimens[1]);
48428c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk    }
48528c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk
486ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    private static native int nativeDetectSurfaceType(Surface surface);
487feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
488ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    private static native int nativeDetectSurfaceDimens(Surface surface,
489a296fece2b974a11bc624fd67b275863f17df867Igor Murashkin            /*out*/int[/*2*/] dimens);
490feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
491ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    private static native int nativeConfigureSurface(Surface surface, int width, int height,
492feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                                                        int pixelFormat);
493feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
494ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    private static native int nativeProduceFrame(Surface surface, byte[] pixelBuffer, int width,
495feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk                                                    int height, int pixelFormat);
496feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
497ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    private static native int nativeSetSurfaceFormat(Surface surface, int pixelFormat);
498feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
499ef14da32804b06bac872c9e0e14ce0e52120a0bdRuben Brunk    private static native int nativeSetSurfaceDimens(Surface surface, int width, int height);
500feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk
5013c8fa3b356fa8f24b55d3dc42d4313297542e9f2Ruben Brunk    private static native long nativeGetSurfaceId(Surface surface);
50228c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk
50328c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk    private static native int nativeSetSurfaceOrientation(Surface surface, int facing,
50428c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk                                                             int sensorOrientation);
50528c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk
50628c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk    private static native int nativeDetectTextureDimens(SurfaceTexture surfaceTexture,
50728c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk            /*out*/int[/*2*/] dimens);
50828c49c9d202a9f4675c1c1e5d4562492d2107b79Ruben Brunk
509feb50af361e4305a25758966b6b5df2738c00259Ruben Brunk}
510