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