1e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck/*
2e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck * Copyright (C) 2016 The Android Open Source Project
3e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck *
4e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck * Licensed under the Apache License, Version 2.0 (the "License");
5e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck * you may not use this file except in compliance with the License.
6e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck * You may obtain a copy of the License at
7e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck *
8e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck *      http://www.apache.org/licenses/LICENSE-2.0
9e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck *
10e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck * Unless required by applicable law or agreed to in writing, software
11e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck * distributed under the License is distributed on an "AS IS" BASIS,
12e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck * See the License for the specific language governing permissions and
14e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck * limitations under the License.
15e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck */
16e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck
17e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reckpackage android.view;
18e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck
19e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reckimport android.annotation.IntDef;
20e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reckimport android.annotation.NonNull;
219580146f5076aaa7c498f86bd3d724c00599f6f4John Reckimport android.annotation.Nullable;
22e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reckimport android.graphics.Bitmap;
239580146f5076aaa7c498f86bd3d724c00599f6f4John Reckimport android.graphics.Rect;
24e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reckimport android.os.Handler;
259580146f5076aaa7c498f86bd3d724c00599f6f4John Reckimport android.view.ViewTreeObserver.OnDrawListener;
26e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck
27e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reckimport java.lang.annotation.Retention;
28e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reckimport java.lang.annotation.RetentionPolicy;
29e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck
30e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck/**
31e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck * Provides a mechanisms to issue pixel copy requests to allow for copy
32e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck * operations from {@link Surface} to {@link Bitmap}
33e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck */
34e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reckpublic final class PixelCopy {
35e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck
36e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck    /** @hide */
37e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck    @Retention(RetentionPolicy.SOURCE)
38e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck    @IntDef({SUCCESS, ERROR_UNKNOWN, ERROR_TIMEOUT, ERROR_SOURCE_NO_DATA,
39e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck        ERROR_SOURCE_INVALID, ERROR_DESTINATION_INVALID})
40e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck    public @interface CopyResultStatus {}
41e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck
42e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck    /** The pixel copy request succeeded */
43e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck    public static final int SUCCESS = 0;
44e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck
45e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck    /** The pixel copy request failed with an unknown error. */
46e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck    public static final int ERROR_UNKNOWN = 1;
47e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck
48e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck    /**
49e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * A timeout occurred while trying to acquire a buffer from the source to
50e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * copy from.
51e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     */
52e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck    public static final int ERROR_TIMEOUT = 2;
53e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck
54e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck    /**
55e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * The source has nothing to copy from. When the source is a {@link Surface}
56e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * this means that no buffers have been queued yet. Wait for the source
57e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * to produce a frame and try again.
58e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     */
59e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck    public static final int ERROR_SOURCE_NO_DATA = 3;
60e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck
61e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck    /**
62e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * It is not possible to copy from the source. This can happen if the source
63e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * is hardware-protected or destroyed.
64e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     */
65e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck    public static final int ERROR_SOURCE_INVALID = 4;
66e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck
67e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck    /**
68e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * The destination isn't a valid copy target. If the destination is a bitmap
69e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * this can occur if the bitmap is too large for the hardware to copy to.
70e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * It can also occur if the destination has been destroyed.
71e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     */
72e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck    public static final int ERROR_DESTINATION_INVALID = 5;
73e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck
74e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck    /**
75e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * Listener for observing the completion of a PixelCopy request.
76e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     */
77e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck    public interface OnPixelCopyFinishedListener {
78e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck        /**
79e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck         * Callback for when a pixel copy request has completed. This will be called
80e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck         * regardless of whether the copy succeeded or failed.
81e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck         *
82e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck         * @param copyResult Contains the resulting status of the copy request.
83e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck         * This will either be {@link PixelCopy#SUCCESS} or one of the
84e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck         * <code>PixelCopy.ERROR_*</code> values.
85e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck         */
86e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck        void onPixelCopyFinished(@CopyResultStatus int copyResult);
87e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck    }
88e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck
89e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck    /**
90e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * Requests for the display content of a {@link SurfaceView} to be copied
91e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * into a provided {@link Bitmap}.
92e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     *
93e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * The contents of the source will be scaled to fit exactly inside the bitmap.
94e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * The pixel format of the source buffer will be converted, as part of the copy,
95e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * to fit the the bitmap's {@link Bitmap.Config}. The most recently queued buffer
96e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * in the SurfaceView's Surface will be used as the source of the copy.
97e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     *
98e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * @param source The source from which to copy
99e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * @param dest The destination of the copy. The source will be scaled to
100e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * match the width, height, and format of this bitmap.
101e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * @param listener Callback for when the pixel copy request completes
102e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * @param listenerThread The callback will be invoked on this Handler when
103e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * the copy is finished.
104e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     */
105e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck    public static void request(@NonNull SurfaceView source, @NonNull Bitmap dest,
106e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck            @NonNull OnPixelCopyFinishedListener listener, @NonNull Handler listenerThread) {
107e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck        request(source.getHolder().getSurface(), dest, listener, listenerThread);
108e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck    }
109e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck
110e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck    /**
1119580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * Requests for the display content of a {@link SurfaceView} to be copied
1129580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * into a provided {@link Bitmap}.
1139580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     *
1149580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * The contents of the source will be scaled to fit exactly inside the bitmap.
1159580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * The pixel format of the source buffer will be converted, as part of the copy,
1169580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * to fit the the bitmap's {@link Bitmap.Config}. The most recently queued buffer
1179580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * in the SurfaceView's Surface will be used as the source of the copy.
1189580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     *
1199580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * @param source The source from which to copy
1209580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * @param srcRect The area of the source to copy from. If this is null
1219580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * the copy area will be the entire surface. The rect will be clamped to
1229580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * the bounds of the Surface.
1239580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * @param dest The destination of the copy. The source will be scaled to
1249580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * match the width, height, and format of this bitmap.
1259580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * @param listener Callback for when the pixel copy request completes
1269580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * @param listenerThread The callback will be invoked on this Handler when
1279580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * the copy is finished.
1289580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     */
1299580146f5076aaa7c498f86bd3d724c00599f6f4John Reck    public static void request(@NonNull SurfaceView source, @Nullable Rect srcRect,
1309580146f5076aaa7c498f86bd3d724c00599f6f4John Reck            @NonNull Bitmap dest, @NonNull OnPixelCopyFinishedListener listener,
1319580146f5076aaa7c498f86bd3d724c00599f6f4John Reck            @NonNull Handler listenerThread) {
1329580146f5076aaa7c498f86bd3d724c00599f6f4John Reck        request(source.getHolder().getSurface(), srcRect,
1339580146f5076aaa7c498f86bd3d724c00599f6f4John Reck                dest, listener, listenerThread);
1349580146f5076aaa7c498f86bd3d724c00599f6f4John Reck    }
1359580146f5076aaa7c498f86bd3d724c00599f6f4John Reck
1369580146f5076aaa7c498f86bd3d724c00599f6f4John Reck    /**
137e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * Requests a copy of the pixels from a {@link Surface} to be copied into
138e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * a provided {@link Bitmap}.
139e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     *
140e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * The contents of the source will be scaled to fit exactly inside the bitmap.
141e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * The pixel format of the source buffer will be converted, as part of the copy,
142e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * to fit the the bitmap's {@link Bitmap.Config}. The most recently queued buffer
143e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * in the Surface will be used as the source of the copy.
144e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     *
145e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * @param source The source from which to copy
146e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * @param dest The destination of the copy. The source will be scaled to
147e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * match the width, height, and format of this bitmap.
148e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * @param listener Callback for when the pixel copy request completes
149e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * @param listenerThread The callback will be invoked on this Handler when
150e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     * the copy is finished.
151e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck     */
152e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck    public static void request(@NonNull Surface source, @NonNull Bitmap dest,
153e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck            @NonNull OnPixelCopyFinishedListener listener, @NonNull Handler listenerThread) {
1549580146f5076aaa7c498f86bd3d724c00599f6f4John Reck        request(source, null, dest, listener, listenerThread);
1559580146f5076aaa7c498f86bd3d724c00599f6f4John Reck    }
1569580146f5076aaa7c498f86bd3d724c00599f6f4John Reck
1579580146f5076aaa7c498f86bd3d724c00599f6f4John Reck    /**
1589580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * Requests a copy of the pixels at the provided {@link Rect} from
1599580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * a {@link Surface} to be copied into a provided {@link Bitmap}.
1609580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     *
1619580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * The contents of the source rect will be scaled to fit exactly inside the bitmap.
1629580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * The pixel format of the source buffer will be converted, as part of the copy,
1639580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * to fit the the bitmap's {@link Bitmap.Config}. The most recently queued buffer
1649580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * in the Surface will be used as the source of the copy.
1659580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     *
1669580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * @param source The source from which to copy
1679580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * @param srcRect The area of the source to copy from. If this is null
1689580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * the copy area will be the entire surface. The rect will be clamped to
1699580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * the bounds of the Surface.
1709580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * @param dest The destination of the copy. The source will be scaled to
1719580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * match the width, height, and format of this bitmap.
1729580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * @param listener Callback for when the pixel copy request completes
1739580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * @param listenerThread The callback will be invoked on this Handler when
1749580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * the copy is finished.
1759580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     */
1769580146f5076aaa7c498f86bd3d724c00599f6f4John Reck    public static void request(@NonNull Surface source, @Nullable Rect srcRect,
1779580146f5076aaa7c498f86bd3d724c00599f6f4John Reck            @NonNull Bitmap dest, @NonNull OnPixelCopyFinishedListener listener,
1789580146f5076aaa7c498f86bd3d724c00599f6f4John Reck            @NonNull Handler listenerThread) {
179e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck        validateBitmapDest(dest);
180f3a51d652ff9fbcb5a41c71c801de71a3b1ece78John Reck        if (!source.isValid()) {
181f3a51d652ff9fbcb5a41c71c801de71a3b1ece78John Reck            throw new IllegalArgumentException("Surface isn't valid, source.isValid() == false");
182f3a51d652ff9fbcb5a41c71c801de71a3b1ece78John Reck        }
1839580146f5076aaa7c498f86bd3d724c00599f6f4John Reck        if (srcRect != null && srcRect.isEmpty()) {
1849580146f5076aaa7c498f86bd3d724c00599f6f4John Reck            throw new IllegalArgumentException("sourceRect is empty");
1859580146f5076aaa7c498f86bd3d724c00599f6f4John Reck        }
186e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck        // TODO: Make this actually async and fast and cool and stuff
1879580146f5076aaa7c498f86bd3d724c00599f6f4John Reck        int result = ThreadedRenderer.copySurfaceInto(source, srcRect, dest);
188e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck        listenerThread.post(new Runnable() {
189e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck            @Override
190e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck            public void run() {
191e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck                listener.onPixelCopyFinished(result);
192e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck            }
193e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck        });
194e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck    }
195e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck
1969580146f5076aaa7c498f86bd3d724c00599f6f4John Reck    /**
1979580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * Requests a copy of the pixels from a {@link Window} to be copied into
1989580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * a provided {@link Bitmap}.
1999580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     *
2009580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * The contents of the source will be scaled to fit exactly inside the bitmap.
2019580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * The pixel format of the source buffer will be converted, as part of the copy,
2029580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * to fit the the bitmap's {@link Bitmap.Config}. The most recently queued buffer
2039580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * in the Window's Surface will be used as the source of the copy.
2049580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     *
2059580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * Note: This is limited to being able to copy from Window's with a non-null
2069580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * DecorView. If {@link Window#peekDecorView()} is null this throws an
2079580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * {@link IllegalArgumentException}. It will similarly throw an exception
2089580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * if the DecorView has not yet acquired a backing surface. It is recommended
2099580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * that {@link OnDrawListener} is used to ensure that at least one draw
2109580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * has happened before trying to copy from the window, otherwise either
2119580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * an {@link IllegalArgumentException} will be thrown or an error will
2129580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * be returned to the {@link OnPixelCopyFinishedListener}.
2139580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     *
2149580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * @param source The source from which to copy
2159580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * @param dest The destination of the copy. The source will be scaled to
2169580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * match the width, height, and format of this bitmap.
2179580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * @param listener Callback for when the pixel copy request completes
2189580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * @param listenerThread The callback will be invoked on this Handler when
2199580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * the copy is finished.
2209580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     */
2219580146f5076aaa7c498f86bd3d724c00599f6f4John Reck    public static void request(@NonNull Window source, @NonNull Bitmap dest,
2229580146f5076aaa7c498f86bd3d724c00599f6f4John Reck            @NonNull OnPixelCopyFinishedListener listener, @NonNull Handler listenerThread) {
2239580146f5076aaa7c498f86bd3d724c00599f6f4John Reck        request(source, null, dest, listener, listenerThread);
2249580146f5076aaa7c498f86bd3d724c00599f6f4John Reck    }
2259580146f5076aaa7c498f86bd3d724c00599f6f4John Reck
2269580146f5076aaa7c498f86bd3d724c00599f6f4John Reck    /**
2279580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * Requests a copy of the pixels at the provided {@link Rect} from
2289580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * a {@link Window} to be copied into a provided {@link Bitmap}.
2299580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     *
2309580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * The contents of the source rect will be scaled to fit exactly inside the bitmap.
2319580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * The pixel format of the source buffer will be converted, as part of the copy,
2329580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * to fit the the bitmap's {@link Bitmap.Config}. The most recently queued buffer
2339580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * in the Window's Surface will be used as the source of the copy.
2349580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     *
2359580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * Note: This is limited to being able to copy from Window's with a non-null
2369580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * DecorView. If {@link Window#peekDecorView()} is null this throws an
2379580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * {@link IllegalArgumentException}. It will similarly throw an exception
2389580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * if the DecorView has not yet acquired a backing surface. It is recommended
2399580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * that {@link OnDrawListener} is used to ensure that at least one draw
2409580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * has happened before trying to copy from the window, otherwise either
2419580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * an {@link IllegalArgumentException} will be thrown or an error will
2429580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * be returned to the {@link OnPixelCopyFinishedListener}.
2439580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     *
2449580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * @param source The source from which to copy
2459580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * @param srcRect The area of the source to copy from. If this is null
2469580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * the copy area will be the entire surface. The rect will be clamped to
2479580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * the bounds of the Surface.
2489580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * @param dest The destination of the copy. The source will be scaled to
2499580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * match the width, height, and format of this bitmap.
2509580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * @param listener Callback for when the pixel copy request completes
2519580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * @param listenerThread The callback will be invoked on this Handler when
2529580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     * the copy is finished.
2539580146f5076aaa7c498f86bd3d724c00599f6f4John Reck     */
2549580146f5076aaa7c498f86bd3d724c00599f6f4John Reck    public static void request(@NonNull Window source, @Nullable Rect srcRect,
2559580146f5076aaa7c498f86bd3d724c00599f6f4John Reck            @NonNull Bitmap dest, @NonNull OnPixelCopyFinishedListener listener,
2569580146f5076aaa7c498f86bd3d724c00599f6f4John Reck            @NonNull Handler listenerThread) {
2579580146f5076aaa7c498f86bd3d724c00599f6f4John Reck        validateBitmapDest(dest);
2589580146f5076aaa7c498f86bd3d724c00599f6f4John Reck        if (source == null) {
2599580146f5076aaa7c498f86bd3d724c00599f6f4John Reck            throw new IllegalArgumentException("source is null");
2609580146f5076aaa7c498f86bd3d724c00599f6f4John Reck        }
2619580146f5076aaa7c498f86bd3d724c00599f6f4John Reck        if (source.peekDecorView() == null) {
2629580146f5076aaa7c498f86bd3d724c00599f6f4John Reck            throw new IllegalArgumentException(
2639580146f5076aaa7c498f86bd3d724c00599f6f4John Reck                    "Only able to copy windows with decor views");
2649580146f5076aaa7c498f86bd3d724c00599f6f4John Reck        }
2659580146f5076aaa7c498f86bd3d724c00599f6f4John Reck        Surface surface = null;
2669580146f5076aaa7c498f86bd3d724c00599f6f4John Reck        if (source.peekDecorView().getViewRootImpl() != null) {
2679580146f5076aaa7c498f86bd3d724c00599f6f4John Reck            surface = source.peekDecorView().getViewRootImpl().mSurface;
2689580146f5076aaa7c498f86bd3d724c00599f6f4John Reck        }
2699580146f5076aaa7c498f86bd3d724c00599f6f4John Reck        if (surface == null || !surface.isValid()) {
2709580146f5076aaa7c498f86bd3d724c00599f6f4John Reck            throw new IllegalArgumentException(
2719580146f5076aaa7c498f86bd3d724c00599f6f4John Reck                    "Window doesn't have a backing surface!");
2729580146f5076aaa7c498f86bd3d724c00599f6f4John Reck        }
2739580146f5076aaa7c498f86bd3d724c00599f6f4John Reck        request(surface, srcRect, dest, listener, listenerThread);
2749580146f5076aaa7c498f86bd3d724c00599f6f4John Reck    }
2759580146f5076aaa7c498f86bd3d724c00599f6f4John Reck
276e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck    private static void validateBitmapDest(Bitmap bitmap) {
277e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck        // TODO: Pre-check max texture dimens if we can
278e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck        if (bitmap == null) {
279e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck            throw new IllegalArgumentException("Bitmap cannot be null");
280e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck        }
281e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck        if (bitmap.isRecycled()) {
282e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck            throw new IllegalArgumentException("Bitmap is recycled");
283e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck        }
284e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck        if (!bitmap.isMutable()) {
285e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck            throw new IllegalArgumentException("Bitmap is immutable");
286e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck        }
287e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck    }
288e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck
289e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck    private PixelCopy() {}
290e94cbc76d560a157c0a0d47181b4ed2a0aadbeb1John Reck}
291