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 android.hardware.camera2.legacy;
18 
19 import android.graphics.ImageFormat;
20 import android.graphics.SurfaceTexture;
21 import android.hardware.Camera;
22 import android.hardware.camera2.CameraCharacteristics;
23 import android.hardware.camera2.CaptureRequest;
24 import android.hardware.camera2.impl.CameraDeviceImpl;
25 import android.hardware.camera2.impl.CaptureResultExtras;
26 import android.hardware.camera2.ICameraDeviceCallbacks;
27 import android.hardware.camera2.params.StreamConfigurationMap;
28 import android.hardware.camera2.utils.ArrayUtils;
29 import android.hardware.camera2.utils.CameraBinderDecorator;
30 import android.hardware.camera2.utils.LongParcelable;
31 import android.hardware.camera2.impl.CameraMetadataNative;
32 import android.hardware.camera2.utils.CameraRuntimeException;
33 import android.os.ConditionVariable;
34 import android.os.Handler;
35 import android.os.HandlerThread;
36 import android.os.RemoteException;
37 import android.util.Log;
38 import android.util.Pair;
39 import android.util.Size;
40 import android.view.Surface;
41 
42 import java.util.ArrayList;
43 import java.util.Arrays;
44 import java.util.Collection;
45 import java.util.List;
46 
47 import static android.hardware.camera2.legacy.LegacyExceptionUtils.*;
48 import static android.hardware.camera2.utils.CameraBinderDecorator.*;
49 import static com.android.internal.util.Preconditions.*;
50 
51 /**
52  * This class emulates the functionality of a Camera2 device using a the old Camera class.
53  *
54  * <p>
55  * There are two main components that are used to implement this:
56  * - A state machine containing valid Camera2 device states ({@link CameraDeviceState}).
57  * - A message-queue based pipeline that manages an old Camera class, and executes capture and
58  *   configuration requests.
59  * </p>
60  */
61 public class LegacyCameraDevice implements AutoCloseable {
62     private final String TAG;
63 
64     private static final boolean DEBUG = false;
65     private final int mCameraId;
66     private final CameraCharacteristics mStaticCharacteristics;
67     private final ICameraDeviceCallbacks mDeviceCallbacks;
68     private final CameraDeviceState mDeviceState = new CameraDeviceState();
69     private List<Surface> mConfiguredSurfaces;
70     private boolean mClosed = false;
71 
72     private final ConditionVariable mIdle = new ConditionVariable(/*open*/true);
73 
74     private final HandlerThread mResultThread = new HandlerThread("ResultThread");
75     private final HandlerThread mCallbackHandlerThread = new HandlerThread("CallbackThread");
76     private final Handler mCallbackHandler;
77     private final Handler mResultHandler;
78     private static final int ILLEGAL_VALUE = -1;
79 
80     // Keep up to date with values in hardware/libhardware/include/hardware/gralloc.h
81     private static final int GRALLOC_USAGE_RENDERSCRIPT = 0x00100000;
82     private static final int GRALLOC_USAGE_SW_READ_OFTEN = 0x00000003;
83     private static final int GRALLOC_USAGE_HW_TEXTURE = 0x00000100;
84     private static final int GRALLOC_USAGE_HW_COMPOSER = 0x00000800;
85     private static final int GRALLOC_USAGE_HW_RENDER = 0x00000200;
86     private static final int GRALLOC_USAGE_HW_VIDEO_ENCODER = 0x00010000;
87 
88     public static final int MAX_DIMEN_FOR_ROUNDING = 1920; // maximum allowed width for rounding
89 
90     // Keep up to date with values in system/core/include/system/window.h
91     public static final int NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW = 1;
92 
getExtrasFromRequest(RequestHolder holder)93     private CaptureResultExtras getExtrasFromRequest(RequestHolder holder) {
94         if (holder == null) {
95             return new CaptureResultExtras(ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE,
96                     ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE);
97         }
98         return new CaptureResultExtras(holder.getRequestId(), holder.getSubsequeceId(),
99                 /*afTriggerId*/0, /*precaptureTriggerId*/0, holder.getFrameNumber(),
100                 /*partialResultCount*/1);
101     }
102 
103     /**
104      * Listener for the camera device state machine.  Calls the appropriate
105      * {@link ICameraDeviceCallbacks} for each state transition.
106      */
107     private final CameraDeviceState.CameraDeviceStateListener mStateListener =
108             new CameraDeviceState.CameraDeviceStateListener() {
109         @Override
110         public void onError(final int errorCode, final RequestHolder holder) {
111             if (DEBUG) {
112                 Log.d(TAG, "onError called, errorCode = " + errorCode);
113             }
114             switch (errorCode) {
115                 /*
116                  * Only be considered idle if we hit a fatal error
117                  * and no further requests can be processed.
118                  */
119                 case CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DISCONNECTED:
120                 case CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_SERVICE:
121                 case CameraDeviceImpl.CameraDeviceCallbacks.ERROR_CAMERA_DEVICE: {
122                     mIdle.open();
123 
124                     if (DEBUG) {
125                         Log.d(TAG, "onError - opening idle");
126                     }
127                 }
128             }
129 
130             final CaptureResultExtras extras = getExtrasFromRequest(holder);
131             mResultHandler.post(new Runnable() {
132                 @Override
133                 public void run() {
134                     if (DEBUG) {
135                         Log.d(TAG, "doing onError callback for request " + holder.getRequestId() +
136                                 ", with error code " + errorCode);
137                     }
138                     try {
139                         mDeviceCallbacks.onDeviceError(errorCode, extras);
140                     } catch (RemoteException e) {
141                         throw new IllegalStateException(
142                                 "Received remote exception during onCameraError callback: ", e);
143                     }
144                 }
145             });
146         }
147 
148         @Override
149         public void onConfiguring() {
150             // Do nothing
151             if (DEBUG) {
152                 Log.d(TAG, "doing onConfiguring callback.");
153             }
154         }
155 
156         @Override
157         public void onIdle() {
158             if (DEBUG) {
159                 Log.d(TAG, "onIdle called");
160             }
161 
162             mIdle.open();
163 
164             mResultHandler.post(new Runnable() {
165                 @Override
166                 public void run() {
167                     if (DEBUG) {
168                         Log.d(TAG, "doing onIdle callback.");
169                     }
170                     try {
171                         mDeviceCallbacks.onDeviceIdle();
172                     } catch (RemoteException e) {
173                         throw new IllegalStateException(
174                                 "Received remote exception during onCameraIdle callback: ", e);
175                     }
176                 }
177             });
178         }
179 
180         @Override
181         public void onBusy() {
182             mIdle.close();
183 
184             if (DEBUG) {
185                 Log.d(TAG, "onBusy called");
186             }
187         }
188 
189         @Override
190         public void onCaptureStarted(final RequestHolder holder, final long timestamp) {
191             final CaptureResultExtras extras = getExtrasFromRequest(holder);
192 
193             mResultHandler.post(new Runnable() {
194                 @Override
195                 public void run() {
196                     if (DEBUG) {
197                         Log.d(TAG, "doing onCaptureStarted callback for request " +
198                                 holder.getRequestId());
199                     }
200                     try {
201                         mDeviceCallbacks.onCaptureStarted(extras, timestamp);
202                     } catch (RemoteException e) {
203                         throw new IllegalStateException(
204                                 "Received remote exception during onCameraError callback: ", e);
205                     }
206                 }
207             });
208         }
209 
210         @Override
211         public void onCaptureResult(final CameraMetadataNative result, final RequestHolder holder) {
212             final CaptureResultExtras extras = getExtrasFromRequest(holder);
213 
214             mResultHandler.post(new Runnable() {
215                 @Override
216                 public void run() {
217                     if (DEBUG) {
218                         Log.d(TAG, "doing onCaptureResult callback for request " +
219                                 holder.getRequestId());
220                     }
221                     try {
222                         mDeviceCallbacks.onResultReceived(result, extras);
223                     } catch (RemoteException e) {
224                         throw new IllegalStateException(
225                                 "Received remote exception during onCameraError callback: ", e);
226                     }
227                 }
228             });
229         }
230     };
231 
232     private final RequestThreadManager mRequestThreadManager;
233 
234     /**
235      * Check if a given surface uses {@link ImageFormat#YUV_420_888} or format that can be readily
236      * converted to this; YV12 and NV21 are the two currently supported formats.
237      *
238      * @param s the surface to check.
239      * @return {@code true} if the surfaces uses {@link ImageFormat#YUV_420_888} or a compatible
240      *          format.
241      */
needsConversion(Surface s)242     static boolean needsConversion(Surface s) throws BufferQueueAbandonedException {
243         int nativeType = detectSurfaceType(s);
244         return nativeType == ImageFormat.YUV_420_888 || nativeType == ImageFormat.YV12 ||
245                 nativeType == ImageFormat.NV21;
246     }
247 
248     /**
249      * Create a new emulated camera device from a given Camera 1 API camera.
250      *
251      * <p>
252      * The {@link Camera} provided to this constructor must already have been successfully opened,
253      * and ownership of the provided camera is passed to this object.  No further calls to the
254      * camera methods should be made following this constructor.
255      * </p>
256      *
257      * @param cameraId the id of the camera.
258      * @param camera an open {@link Camera} device.
259      * @param characteristics the static camera characteristics for this camera device
260      * @param callbacks {@link ICameraDeviceCallbacks} callbacks to call for Camera2 API operations.
261      */
LegacyCameraDevice(int cameraId, Camera camera, CameraCharacteristics characteristics, ICameraDeviceCallbacks callbacks)262     public LegacyCameraDevice(int cameraId, Camera camera, CameraCharacteristics characteristics,
263             ICameraDeviceCallbacks callbacks) {
264         mCameraId = cameraId;
265         mDeviceCallbacks = callbacks;
266         TAG = String.format("CameraDevice-%d-LE", mCameraId);
267 
268         mResultThread.start();
269         mResultHandler = new Handler(mResultThread.getLooper());
270         mCallbackHandlerThread.start();
271         mCallbackHandler = new Handler(mCallbackHandlerThread.getLooper());
272         mDeviceState.setCameraDeviceCallbacks(mCallbackHandler, mStateListener);
273         mStaticCharacteristics = characteristics;
274         mRequestThreadManager =
275                 new RequestThreadManager(cameraId, camera, characteristics, mDeviceState);
276         mRequestThreadManager.start();
277     }
278 
279     /**
280      * Configure the device with a set of output surfaces.
281      *
282      * <p>Using empty or {@code null} {@code outputs} is the same as unconfiguring.</p>
283      *
284      * <p>Every surface in {@code outputs} must be non-{@code null}.</p>
285      *
286      * @param outputs a list of surfaces to set.
287      * @return an error code for this binder operation, or {@link NO_ERROR}
288      *          on success.
289      */
configureOutputs(List<Surface> outputs)290     public int configureOutputs(List<Surface> outputs) {
291         List<Pair<Surface, Size>> sizedSurfaces = new ArrayList<>();
292         if (outputs != null) {
293             for (Surface output : outputs) {
294                 if (output == null) {
295                     Log.e(TAG, "configureOutputs - null outputs are not allowed");
296                     return BAD_VALUE;
297                 }
298                 if (!output.isValid()) {
299                     Log.e(TAG, "configureOutputs - invalid output surfaces are not allowed");
300                     return BAD_VALUE;
301                 }
302                 StreamConfigurationMap streamConfigurations = mStaticCharacteristics.
303                         get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
304 
305                 // Validate surface size and format.
306                 try {
307                     Size s = getSurfaceSize(output);
308                     int surfaceType = detectSurfaceType(output);
309 
310                     boolean flexibleConsumer = isFlexibleConsumer(output);
311 
312                     Size[] sizes = streamConfigurations.getOutputSizes(surfaceType);
313                     if (sizes == null) {
314                         // WAR: Override default format to IMPLEMENTATION_DEFINED for b/9487482
315                         if ((surfaceType >= LegacyMetadataMapper.HAL_PIXEL_FORMAT_RGBA_8888 &&
316                             surfaceType <= LegacyMetadataMapper.HAL_PIXEL_FORMAT_BGRA_8888)) {
317 
318                             // YUV_420_888 is always present in LEGACY for all
319                             // IMPLEMENTATION_DEFINED output sizes, and is publicly visible in the
320                             // API (i.e. {@code #getOutputSizes} works here).
321                             sizes = streamConfigurations.getOutputSizes(ImageFormat.YUV_420_888);
322                         } else if (surfaceType == LegacyMetadataMapper.HAL_PIXEL_FORMAT_BLOB) {
323                             sizes = streamConfigurations.getOutputSizes(ImageFormat.JPEG);
324                         }
325                     }
326 
327                     if (!ArrayUtils.contains(sizes, s)) {
328                         if (flexibleConsumer && (s = findClosestSize(s, sizes)) != null) {
329                             sizedSurfaces.add(new Pair<>(output, s));
330                         } else {
331                             String reason = (sizes == null) ? "format is invalid." :
332                                     ("size not in valid set: " + Arrays.toString(sizes));
333                             Log.e(TAG, String.format("Surface with size (w=%d, h=%d) and format " +
334                                     "0x%x is not valid, %s", s.getWidth(), s.getHeight(),
335                                     surfaceType, reason));
336                             return BAD_VALUE;
337                         }
338                     } else {
339                         sizedSurfaces.add(new Pair<>(output, s));
340                     }
341                     // Lock down the size before configuration
342                     setSurfaceDimens(output, s.getWidth(), s.getHeight());
343                 } catch (BufferQueueAbandonedException e) {
344                     Log.e(TAG, "Surface bufferqueue is abandoned, cannot configure as output: ", e);
345                     return BAD_VALUE;
346                 }
347 
348             }
349         }
350 
351         boolean success = false;
352         if (mDeviceState.setConfiguring()) {
353             mRequestThreadManager.configure(sizedSurfaces);
354             success = mDeviceState.setIdle();
355         }
356 
357         if (success) {
358             mConfiguredSurfaces = outputs != null ? new ArrayList<>(outputs) : null;
359         } else {
360             return CameraBinderDecorator.INVALID_OPERATION;
361         }
362         return CameraBinderDecorator.NO_ERROR;
363     }
364 
365     /**
366      * Submit a burst of capture requests.
367      *
368      * @param requestList a list of capture requests to execute.
369      * @param repeating {@code true} if this burst is repeating.
370      * @param frameNumber an output argument that contains either the frame number of the last frame
371      *                    that will be returned for this request, or the frame number of the last
372      *                    frame that will be returned for the current repeating request if this
373      *                    burst is set to be repeating.
374      * @return the request id.
375      */
submitRequestList(List<CaptureRequest> requestList, boolean repeating, LongParcelable frameNumber)376     public int submitRequestList(List<CaptureRequest> requestList, boolean repeating,
377             /*out*/LongParcelable frameNumber) {
378         if (requestList == null || requestList.isEmpty()) {
379             Log.e(TAG, "submitRequestList - Empty/null requests are not allowed");
380             return BAD_VALUE;
381         }
382 
383         List<Long> surfaceIds = (mConfiguredSurfaces == null) ? new ArrayList<Long>() :
384                 getSurfaceIds(mConfiguredSurfaces);
385 
386         // Make sure that there all requests have at least 1 surface; all surfaces are non-null
387         for (CaptureRequest request : requestList) {
388             if (request.getTargets().isEmpty()) {
389                 Log.e(TAG, "submitRequestList - "
390                         + "Each request must have at least one Surface target");
391                 return BAD_VALUE;
392             }
393 
394             for (Surface surface : request.getTargets()) {
395                 if (surface == null) {
396                     Log.e(TAG, "submitRequestList - Null Surface targets are not allowed");
397                     return BAD_VALUE;
398                 } else if (mConfiguredSurfaces == null) {
399                     Log.e(TAG, "submitRequestList - must configure " +
400                             " device with valid surfaces before submitting requests");
401                     return INVALID_OPERATION;
402                 } else if (!containsSurfaceId(surface, surfaceIds)) {
403                     Log.e(TAG, "submitRequestList - cannot use a surface that wasn't configured");
404                     return BAD_VALUE;
405                 }
406             }
407         }
408 
409         // TODO: further validation of request here
410         mIdle.close();
411         return mRequestThreadManager.submitCaptureRequests(requestList, repeating,
412                 frameNumber);
413     }
414 
415     /**
416      * Submit a single capture request.
417      *
418      * @param request the capture request to execute.
419      * @param repeating {@code true} if this request is repeating.
420      * @param frameNumber an output argument that contains either the frame number of the last frame
421      *                    that will be returned for this request, or the frame number of the last
422      *                    frame that will be returned for the current repeating request if this
423      *                    request is set to be repeating.
424      * @return the request id.
425      */
submitRequest(CaptureRequest request, boolean repeating, LongParcelable frameNumber)426     public int submitRequest(CaptureRequest request, boolean repeating,
427             /*out*/LongParcelable frameNumber) {
428         ArrayList<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
429         requestList.add(request);
430         return submitRequestList(requestList, repeating, frameNumber);
431     }
432 
433     /**
434      * Cancel the repeating request with the given request id.
435      *
436      * @param requestId the request id of the request to cancel.
437      * @return the last frame number to be returned from the HAL for the given repeating request, or
438      *          {@code INVALID_FRAME} if none exists.
439      */
cancelRequest(int requestId)440     public long cancelRequest(int requestId) {
441         return mRequestThreadManager.cancelRepeating(requestId);
442     }
443 
444     /**
445      * Block until the {@link ICameraDeviceCallbacks#onCameraIdle()} callback is received.
446      */
waitUntilIdle()447     public void waitUntilIdle()  {
448         mIdle.block();
449     }
450 
451     /**
452      * Flush any pending requests.
453      *
454      * @return the last frame number.
455      */
flush()456     public long flush() {
457         long lastFrame = mRequestThreadManager.flush();
458         waitUntilIdle();
459         return lastFrame;
460     }
461 
462     /**
463      * Return {@code true} if the device has been closed.
464      */
isClosed()465     public boolean isClosed() {
466         return mClosed;
467     }
468 
469     @Override
close()470     public void close() {
471         mRequestThreadManager.quit();
472         mCallbackHandlerThread.quitSafely();
473         mResultThread.quitSafely();
474 
475         try {
476             mCallbackHandlerThread.join();
477         } catch (InterruptedException e) {
478             Log.e(TAG, String.format("Thread %s (%d) interrupted while quitting.",
479                     mCallbackHandlerThread.getName(), mCallbackHandlerThread.getId()));
480         }
481 
482         try {
483             mResultThread.join();
484         } catch (InterruptedException e) {
485             Log.e(TAG, String.format("Thread %s (%d) interrupted while quitting.",
486                     mResultThread.getName(), mResultThread.getId()));
487         }
488 
489         mClosed = true;
490     }
491 
492     @Override
finalize()493     protected void finalize() throws Throwable {
494         try {
495             close();
496         } catch (CameraRuntimeException e) {
497             Log.e(TAG, "Got error while trying to finalize, ignoring: " + e.getMessage());
498         } finally {
499             super.finalize();
500         }
501     }
502 
findEuclidDistSquare(Size a, Size b)503     static long findEuclidDistSquare(Size a, Size b) {
504         long d0 = a.getWidth() - b.getWidth();
505         long d1 = a.getHeight() - b.getHeight();
506         return d0 * d0 + d1 * d1;
507     }
508 
509     // Keep up to date with rounding behavior in
510     // frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
findClosestSize(Size size, Size[] supportedSizes)511     static Size findClosestSize(Size size, Size[] supportedSizes) {
512         if (size == null || supportedSizes == null) {
513             return null;
514         }
515         Size bestSize = null;
516         for (Size s : supportedSizes) {
517             if (s.equals(size)) {
518                 return size;
519             } else if (s.getWidth() <= MAX_DIMEN_FOR_ROUNDING && (bestSize == null ||
520                     LegacyCameraDevice.findEuclidDistSquare(size, s) <
521                     LegacyCameraDevice.findEuclidDistSquare(bestSize, s))) {
522                 bestSize = s;
523             }
524         }
525         return bestSize;
526     }
527 
528     /**
529      * Query the surface for its currently configured default buffer size.
530      * @param surface a non-{@code null} {@code Surface}
531      * @return the width and height of the surface
532      *
533      * @throws NullPointerException if the {@code surface} was {@code null}
534      * @throws BufferQueueAbandonedException if the {@code surface} was invalid
535      */
getSurfaceSize(Surface surface)536     public static Size getSurfaceSize(Surface surface) throws BufferQueueAbandonedException {
537         checkNotNull(surface);
538 
539         int[] dimens = new int[2];
540         LegacyExceptionUtils.throwOnError(nativeDetectSurfaceDimens(surface, /*out*/dimens));
541 
542         return new Size(dimens[0], dimens[1]);
543     }
544 
isFlexibleConsumer(Surface output)545     public static boolean isFlexibleConsumer(Surface output) {
546         int usageFlags = detectSurfaceUsageFlags(output);
547 
548         // Keep up to date with allowed consumer types in
549         // frameworks/av/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
550         int disallowedFlags = GRALLOC_USAGE_HW_VIDEO_ENCODER | GRALLOC_USAGE_RENDERSCRIPT;
551         int allowedFlags = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_OFTEN |
552             GRALLOC_USAGE_HW_COMPOSER;
553         boolean flexibleConsumer = ((usageFlags & disallowedFlags) == 0 &&
554                 (usageFlags & allowedFlags) != 0);
555         return flexibleConsumer;
556     }
557 
isPreviewConsumer(Surface output)558     public static boolean isPreviewConsumer(Surface output) {
559         int usageFlags = detectSurfaceUsageFlags(output);
560         int disallowedFlags = GRALLOC_USAGE_HW_VIDEO_ENCODER | GRALLOC_USAGE_RENDERSCRIPT |
561                 GRALLOC_USAGE_SW_READ_OFTEN;
562         int allowedFlags = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER |
563                 GRALLOC_USAGE_HW_RENDER;
564         boolean previewConsumer = ((usageFlags & disallowedFlags) == 0 &&
565                 (usageFlags & allowedFlags) != 0);
566         int surfaceFormat = ImageFormat.UNKNOWN;
567         try {
568             surfaceFormat = detectSurfaceType(output);
569         } catch(BufferQueueAbandonedException e) {
570             throw new IllegalArgumentException("Surface was abandoned", e);
571         }
572 
573         return previewConsumer;
574     }
575 
isVideoEncoderConsumer(Surface output)576     public static boolean isVideoEncoderConsumer(Surface output) {
577         int usageFlags = detectSurfaceUsageFlags(output);
578         int disallowedFlags = GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_HW_COMPOSER |
579                 GRALLOC_USAGE_RENDERSCRIPT | GRALLOC_USAGE_SW_READ_OFTEN;
580         int allowedFlags = GRALLOC_USAGE_HW_VIDEO_ENCODER;
581         boolean videoEncoderConsumer = ((usageFlags & disallowedFlags) == 0 &&
582                 (usageFlags & allowedFlags) != 0);
583 
584         int surfaceFormat = ImageFormat.UNKNOWN;
585         try {
586             surfaceFormat = detectSurfaceType(output);
587         } catch(BufferQueueAbandonedException e) {
588             throw new IllegalArgumentException("Surface was abandoned", e);
589         }
590 
591         return videoEncoderConsumer;
592     }
593 
594     /**
595      * Query the surface for its currently configured usage flags
596      */
detectSurfaceUsageFlags(Surface surface)597     static int detectSurfaceUsageFlags(Surface surface) {
598         checkNotNull(surface);
599         return nativeDetectSurfaceUsageFlags(surface);
600     }
601 
602     /**
603      * Query the surface for its currently configured format
604      */
detectSurfaceType(Surface surface)605     public static int detectSurfaceType(Surface surface) throws BufferQueueAbandonedException {
606         checkNotNull(surface);
607         return LegacyExceptionUtils.throwOnError(nativeDetectSurfaceType(surface));
608     }
609 
610     /**
611      * Query the surface for its currently configured dataspace
612      */
detectSurfaceDataspace(Surface surface)613     public static int detectSurfaceDataspace(Surface surface) throws BufferQueueAbandonedException {
614         checkNotNull(surface);
615         return LegacyExceptionUtils.throwOnError(nativeDetectSurfaceDataspace(surface));
616     }
617 
configureSurface(Surface surface, int width, int height, int pixelFormat)618     static void configureSurface(Surface surface, int width, int height,
619                                  int pixelFormat) throws BufferQueueAbandonedException {
620         checkNotNull(surface);
621         checkArgumentPositive(width, "width must be positive.");
622         checkArgumentPositive(height, "height must be positive.");
623 
624         LegacyExceptionUtils.throwOnError(nativeConfigureSurface(surface, width, height,
625                 pixelFormat));
626     }
627 
produceFrame(Surface surface, byte[] pixelBuffer, int width, int height, int pixelFormat)628     static void produceFrame(Surface surface, byte[] pixelBuffer, int width,
629                              int height, int pixelFormat)
630             throws BufferQueueAbandonedException {
631         checkNotNull(surface);
632         checkNotNull(pixelBuffer);
633         checkArgumentPositive(width, "width must be positive.");
634         checkArgumentPositive(height, "height must be positive.");
635 
636         LegacyExceptionUtils.throwOnError(nativeProduceFrame(surface, pixelBuffer, width, height,
637                 pixelFormat));
638     }
639 
setSurfaceFormat(Surface surface, int pixelFormat)640     static void setSurfaceFormat(Surface surface, int pixelFormat)
641             throws BufferQueueAbandonedException {
642         checkNotNull(surface);
643 
644         LegacyExceptionUtils.throwOnError(nativeSetSurfaceFormat(surface, pixelFormat));
645     }
646 
setSurfaceDimens(Surface surface, int width, int height)647     static void setSurfaceDimens(Surface surface, int width, int height)
648             throws BufferQueueAbandonedException {
649         checkNotNull(surface);
650         checkArgumentPositive(width, "width must be positive.");
651         checkArgumentPositive(height, "height must be positive.");
652 
653         LegacyExceptionUtils.throwOnError(nativeSetSurfaceDimens(surface, width, height));
654     }
655 
getSurfaceId(Surface surface)656     static long getSurfaceId(Surface surface) {
657         checkNotNull(surface);
658         return nativeGetSurfaceId(surface);
659     }
660 
getSurfaceIds(Collection<Surface> surfaces)661     static List<Long> getSurfaceIds(Collection<Surface> surfaces) {
662         if (surfaces == null) {
663             throw new NullPointerException("Null argument surfaces");
664         }
665         List<Long> surfaceIds = new ArrayList<>();
666         for (Surface s : surfaces) {
667             long id = getSurfaceId(s);
668             if (id == 0) {
669                 throw new IllegalStateException(
670                         "Configured surface had null native GraphicBufferProducer pointer!");
671             }
672             surfaceIds.add(id);
673         }
674         return surfaceIds;
675     }
676 
containsSurfaceId(Surface s, Collection<Long> ids)677     static boolean containsSurfaceId(Surface s, Collection<Long> ids) {
678         long id = getSurfaceId(s);
679         return ids.contains(id);
680     }
681 
setSurfaceOrientation(Surface surface, int facing, int sensorOrientation)682     static void setSurfaceOrientation(Surface surface, int facing, int sensorOrientation)
683             throws BufferQueueAbandonedException {
684         checkNotNull(surface);
685         LegacyExceptionUtils.throwOnError(nativeSetSurfaceOrientation(surface, facing,
686                 sensorOrientation));
687     }
688 
getTextureSize(SurfaceTexture surfaceTexture)689     static Size getTextureSize(SurfaceTexture surfaceTexture)
690             throws BufferQueueAbandonedException {
691         checkNotNull(surfaceTexture);
692 
693         int[] dimens = new int[2];
694         LegacyExceptionUtils.throwOnError(nativeDetectTextureDimens(surfaceTexture,
695                 /*out*/dimens));
696 
697         return new Size(dimens[0], dimens[1]);
698     }
699 
setNextTimestamp(Surface surface, long timestamp)700     static void setNextTimestamp(Surface surface, long timestamp)
701             throws BufferQueueAbandonedException {
702         checkNotNull(surface);
703         LegacyExceptionUtils.throwOnError(nativeSetNextTimestamp(surface, timestamp));
704     }
705 
setScalingMode(Surface surface, int mode)706     static void setScalingMode(Surface surface, int mode)
707             throws BufferQueueAbandonedException {
708         checkNotNull(surface);
709         LegacyExceptionUtils.throwOnError(nativeSetScalingMode(surface, mode));
710     }
711 
712 
nativeDetectSurfaceType(Surface surface)713     private static native int nativeDetectSurfaceType(Surface surface);
714 
nativeDetectSurfaceDataspace(Surface surface)715     private static native int nativeDetectSurfaceDataspace(Surface surface);
716 
nativeDetectSurfaceDimens(Surface surface, int[ ] dimens)717     private static native int nativeDetectSurfaceDimens(Surface surface,
718             /*out*/int[/*2*/] dimens);
719 
nativeConfigureSurface(Surface surface, int width, int height, int pixelFormat)720     private static native int nativeConfigureSurface(Surface surface, int width, int height,
721                                                         int pixelFormat);
722 
nativeProduceFrame(Surface surface, byte[] pixelBuffer, int width, int height, int pixelFormat)723     private static native int nativeProduceFrame(Surface surface, byte[] pixelBuffer, int width,
724                                                     int height, int pixelFormat);
725 
nativeSetSurfaceFormat(Surface surface, int pixelFormat)726     private static native int nativeSetSurfaceFormat(Surface surface, int pixelFormat);
727 
nativeSetSurfaceDimens(Surface surface, int width, int height)728     private static native int nativeSetSurfaceDimens(Surface surface, int width, int height);
729 
nativeGetSurfaceId(Surface surface)730     private static native long nativeGetSurfaceId(Surface surface);
731 
nativeSetSurfaceOrientation(Surface surface, int facing, int sensorOrientation)732     private static native int nativeSetSurfaceOrientation(Surface surface, int facing,
733                                                              int sensorOrientation);
734 
nativeDetectTextureDimens(SurfaceTexture surfaceTexture, int[ ] dimens)735     private static native int nativeDetectTextureDimens(SurfaceTexture surfaceTexture,
736             /*out*/int[/*2*/] dimens);
737 
nativeSetNextTimestamp(Surface surface, long timestamp)738     private static native int nativeSetNextTimestamp(Surface surface, long timestamp);
739 
nativeDetectSurfaceUsageFlags(Surface surface)740     private static native int nativeDetectSurfaceUsageFlags(Surface surface);
741 
nativeSetScalingMode(Surface surface, int scalingMode)742     private static native int nativeSetScalingMode(Surface surface, int scalingMode);
743 
nativeGetJpegFooterSize()744     static native int nativeGetJpegFooterSize();
745 }
746