blob: 95c930c5264d318ad726b5593513230355264792 [file] [log] [blame]
John Recke94cbc72016-04-25 13:03:44 -07001/*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.view;
18
19import android.annotation.IntDef;
20import android.annotation.NonNull;
21import android.graphics.Bitmap;
22import android.os.Handler;
23
24import java.lang.annotation.Retention;
25import java.lang.annotation.RetentionPolicy;
26
27/**
28 * Provides a mechanisms to issue pixel copy requests to allow for copy
29 * operations from {@link Surface} to {@link Bitmap}
30 */
31public final class PixelCopy {
32
33 /** @hide */
34 @Retention(RetentionPolicy.SOURCE)
35 @IntDef({SUCCESS, ERROR_UNKNOWN, ERROR_TIMEOUT, ERROR_SOURCE_NO_DATA,
36 ERROR_SOURCE_INVALID, ERROR_DESTINATION_INVALID})
37 public @interface CopyResultStatus {}
38
39 /** The pixel copy request succeeded */
40 public static final int SUCCESS = 0;
41
42 /** The pixel copy request failed with an unknown error. */
43 public static final int ERROR_UNKNOWN = 1;
44
45 /**
46 * A timeout occurred while trying to acquire a buffer from the source to
47 * copy from.
48 */
49 public static final int ERROR_TIMEOUT = 2;
50
51 /**
52 * The source has nothing to copy from. When the source is a {@link Surface}
53 * this means that no buffers have been queued yet. Wait for the source
54 * to produce a frame and try again.
55 */
56 public static final int ERROR_SOURCE_NO_DATA = 3;
57
58 /**
59 * It is not possible to copy from the source. This can happen if the source
60 * is hardware-protected or destroyed.
61 */
62 public static final int ERROR_SOURCE_INVALID = 4;
63
64 /**
65 * The destination isn't a valid copy target. If the destination is a bitmap
66 * this can occur if the bitmap is too large for the hardware to copy to.
67 * It can also occur if the destination has been destroyed.
68 */
69 public static final int ERROR_DESTINATION_INVALID = 5;
70
71 /**
72 * Listener for observing the completion of a PixelCopy request.
73 */
74 public interface OnPixelCopyFinishedListener {
75 /**
76 * Callback for when a pixel copy request has completed. This will be called
77 * regardless of whether the copy succeeded or failed.
78 *
79 * @param copyResult Contains the resulting status of the copy request.
80 * This will either be {@link PixelCopy#SUCCESS} or one of the
81 * <code>PixelCopy.ERROR_*</code> values.
82 */
83 void onPixelCopyFinished(@CopyResultStatus int copyResult);
84 }
85
86 /**
87 * Requests for the display content of a {@link SurfaceView} to be copied
88 * into a provided {@link Bitmap}.
89 *
90 * The contents of the source will be scaled to fit exactly inside the bitmap.
91 * The pixel format of the source buffer will be converted, as part of the copy,
92 * to fit the the bitmap's {@link Bitmap.Config}. The most recently queued buffer
93 * in the SurfaceView's Surface will be used as the source of the copy.
94 *
95 * @param source The source from which to copy
96 * @param dest The destination of the copy. The source will be scaled to
97 * match the width, height, and format of this bitmap.
98 * @param listener Callback for when the pixel copy request completes
99 * @param listenerThread The callback will be invoked on this Handler when
100 * the copy is finished.
101 */
102 public static void request(@NonNull SurfaceView source, @NonNull Bitmap dest,
103 @NonNull OnPixelCopyFinishedListener listener, @NonNull Handler listenerThread) {
104 request(source.getHolder().getSurface(), dest, listener, listenerThread);
105 }
106
107 /**
108 * Requests a copy of the pixels from a {@link Surface} to be copied into
109 * a provided {@link Bitmap}.
110 *
111 * The contents of the source will be scaled to fit exactly inside the bitmap.
112 * The pixel format of the source buffer will be converted, as part of the copy,
113 * to fit the the bitmap's {@link Bitmap.Config}. The most recently queued buffer
114 * in the Surface will be used as the source of the copy.
115 *
116 * @param source The source from which to copy
117 * @param dest The destination of the copy. The source will be scaled to
118 * match the width, height, and format of this bitmap.
119 * @param listener Callback for when the pixel copy request completes
120 * @param listenerThread The callback will be invoked on this Handler when
121 * the copy is finished.
122 */
123 public static void request(@NonNull Surface source, @NonNull Bitmap dest,
124 @NonNull OnPixelCopyFinishedListener listener, @NonNull Handler listenerThread) {
125 validateBitmapDest(dest);
126 // TODO: Make this actually async and fast and cool and stuff
127 int result = ThreadedRenderer.copySurfaceInto(source, dest);
128 listenerThread.post(new Runnable() {
129 @Override
130 public void run() {
131 listener.onPixelCopyFinished(result);
132 }
133 });
134 }
135
136 private static void validateBitmapDest(Bitmap bitmap) {
137 // TODO: Pre-check max texture dimens if we can
138 if (bitmap == null) {
139 throw new IllegalArgumentException("Bitmap cannot be null");
140 }
141 if (bitmap.isRecycled()) {
142 throw new IllegalArgumentException("Bitmap is recycled");
143 }
144 if (!bitmap.isMutable()) {
145 throw new IllegalArgumentException("Bitmap is immutable");
146 }
147 }
148
149 private PixelCopy() {}
150}