Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4c9cbf85 authored by John Reck's avatar John Reck Committed by Android (Google) Code Review
Browse files

Merge "Update PixelCopy for API feedback"

parents 2f2271e0 03256ddf
Loading
Loading
Loading
Loading
+18 −12
Original line number Diff line number Diff line
@@ -49575,16 +49575,13 @@ package android.view {
  }
  public final class PixelCopy {
    method @NonNull public static android.view.PixelCopy.Request ofSurface(@NonNull android.view.Surface, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.view.PixelCopy.CopyResult>);
    method @NonNull public static android.view.PixelCopy.Request ofSurface(@NonNull android.view.SurfaceView, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.view.PixelCopy.CopyResult>);
    method @NonNull public static android.view.PixelCopy.Request ofWindow(@NonNull android.view.Window, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.view.PixelCopy.CopyResult>);
    method @NonNull public static android.view.PixelCopy.Request ofWindow(@NonNull android.view.View, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.view.PixelCopy.CopyResult>);
    method public static void request(@NonNull android.view.SurfaceView, @NonNull android.graphics.Bitmap, @NonNull android.view.PixelCopy.OnPixelCopyFinishedListener, @NonNull android.os.Handler);
    method public static void request(@NonNull android.view.SurfaceView, @Nullable android.graphics.Rect, @NonNull android.graphics.Bitmap, @NonNull android.view.PixelCopy.OnPixelCopyFinishedListener, @NonNull android.os.Handler);
    method public static void request(@NonNull android.view.Surface, @NonNull android.graphics.Bitmap, @NonNull android.view.PixelCopy.OnPixelCopyFinishedListener, @NonNull android.os.Handler);
    method public static void request(@NonNull android.view.Surface, @Nullable android.graphics.Rect, @NonNull android.graphics.Bitmap, @NonNull android.view.PixelCopy.OnPixelCopyFinishedListener, @NonNull android.os.Handler);
    method public static void request(@NonNull android.view.Window, @NonNull android.graphics.Bitmap, @NonNull android.view.PixelCopy.OnPixelCopyFinishedListener, @NonNull android.os.Handler);
    method public static void request(@NonNull android.view.Window, @Nullable android.graphics.Rect, @NonNull android.graphics.Bitmap, @NonNull android.view.PixelCopy.OnPixelCopyFinishedListener, @NonNull android.os.Handler);
    method public static void request(@NonNull android.view.PixelCopy.Request);
    field public static final int ERROR_DESTINATION_INVALID = 5; // 0x5
    field public static final int ERROR_SOURCE_INVALID = 4; // 0x4
    field public static final int ERROR_SOURCE_NO_DATA = 3; // 0x3
@@ -49593,19 +49590,28 @@ package android.view {
    field public static final int SUCCESS = 0; // 0x0
  }
  public static final class PixelCopy.CopyResult {
    method @NonNull public android.graphics.Bitmap getBitmap();
    method public int getStatus();
  }
  public static interface PixelCopy.OnPixelCopyFinishedListener {
    method public void onPixelCopyFinished(int);
  }
  public static final class PixelCopy.Request {
    method public void request();
    method @NonNull public android.view.PixelCopy.Request setDestinationBitmap(@Nullable android.graphics.Bitmap);
    method @NonNull public android.view.PixelCopy.Request setSourceRect(@Nullable android.graphics.Rect);
    method @Nullable public android.graphics.Bitmap getDestinationBitmap();
    method @Nullable public android.graphics.Rect getSourceRect();
    method @NonNull public static android.view.PixelCopy.Request.Builder ofSurface(@NonNull android.view.Surface, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.view.PixelCopy.Result>);
    method @NonNull public static android.view.PixelCopy.Request.Builder ofSurface(@NonNull android.view.SurfaceView, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.view.PixelCopy.Result>);
    method @NonNull public static android.view.PixelCopy.Request.Builder ofWindow(@NonNull android.view.Window, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.view.PixelCopy.Result>);
    method @NonNull public static android.view.PixelCopy.Request.Builder ofWindow(@NonNull android.view.View, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.view.PixelCopy.Result>);
  }
  public static final class PixelCopy.Request.Builder {
    method @NonNull public android.view.PixelCopy.Request build();
    method @NonNull public android.view.PixelCopy.Request.Builder setDestinationBitmap(@Nullable android.graphics.Bitmap);
    method @NonNull public android.view.PixelCopy.Request.Builder setSourceRect(@Nullable android.graphics.Rect);
  }
  public static final class PixelCopy.Result {
    method @NonNull public android.graphics.Bitmap getBitmap();
    method public int getStatus();
  }
  public final class PointerIcon implements android.os.Parcelable {
+176 −118
Original line number Diff line number Diff line
@@ -311,11 +311,11 @@ public final class PixelCopy {
    /**
     * Contains the result of a PixelCopy request
     */
    public static final class CopyResult {
    public static final class Result {
        private int mStatus;
        private Bitmap mBitmap;

        private CopyResult(@CopyResultStatus int status, Bitmap bitmap) {
        private Result(@CopyResultStatus int status, Bitmap bitmap) {
            mStatus = status;
            mBitmap = bitmap;
        }
@@ -335,8 +335,8 @@ public final class PixelCopy {

        /**
         * If the PixelCopy {@link Request} was given a destination bitmap with
         * {@link Request#setDestinationBitmap(Bitmap)} then the returned bitmap will be the same
         * as the one given. If no destination bitmap was provided, then this
         * {@link Request.Builder#setDestinationBitmap(Bitmap)} then the returned bitmap will be
         * the same as the one given. If no destination bitmap was provided, then this
         * will contain the automatically allocated Bitmap to hold the result.
         *
         * @return the Bitmap the copy request was stored in.
@@ -349,76 +349,92 @@ public final class PixelCopy {
    }

    /**
     * A builder to create the complete PixelCopy request, which is then executed by calling
     * {@link #request()}
     * Represents a PixelCopy request.
     *
     * To create a copy request, use either of the PixelCopy.Request.ofWindow or
     * PixelCopy.Request.ofSurface factories to create a {@link Request.Builder} for the
     * given source content. After setting any optional parameters, such as
     * {@link Builder#setSourceRect(Rect)}, build the request with {@link Builder#build()} and
     * then execute it with {@link PixelCopy#request(Request)}
     */
    public static final class Request {
        private final Surface mSource;
        private final Consumer<Result> mListener;
        private final Executor mListenerThread;
        private final Rect mSourceInsets;
        private Rect mSrcRect;
        private Bitmap mDest;

        private Request(Surface source, Rect sourceInsets, Executor listenerThread,
                        Consumer<CopyResult> listener) {
                        Consumer<Result> listener) {
            this.mSource = source;
            this.mSourceInsets = sourceInsets;
            this.mListenerThread = listenerThread;
            this.mListener = listener;
        }

        private final Surface mSource;
        private final Consumer<CopyResult> mListener;
        private final Executor mListenerThread;
        private final Rect mSourceInsets;
        private Rect mSrcRect;
        private Bitmap mDest;
        /**
         * A builder to create the complete PixelCopy request, which is then executed by calling
         * {@link #request(Request)} with the built request returned from {@link #build()}
         */
        public static final class Builder {
            private Request mRequest;

            private Builder(Request request) {
                mRequest = request;
            }

            private void requireNotBuilt() {
                if (mRequest == null) {
                    throw new IllegalStateException("build() already called on this builder");
                }
            }

            /**
         * Sets the region of the source to copy from. By default, the entire source is copied to
         * the output. If only a subset of the source is necessary to be copied, specifying a
         * srcRect will improve performance by reducing
             * Sets the region of the source to copy from. By default, the entire source is copied
             * to the output. If only a subset of the source is necessary to be copied, specifying
             * a srcRect will improve performance by reducing
             * the amount of data being copied.
             *
             * @param srcRect The area of the source to read from. Null or empty will be treated to
             *                mean the entire source
             * @return this
             */
        public @NonNull Request setSourceRect(@Nullable Rect srcRect) {
            this.mSrcRect = srcRect;
            public @NonNull Builder setSourceRect(@Nullable Rect srcRect) {
                requireNotBuilt();
                mRequest.mSrcRect = srcRect;
                return this;
            }

            /**
         * Specifies the output bitmap in which to store the result. By default, a Bitmap of format
         * {@link android.graphics.Bitmap.Config#ARGB_8888} with a width & height matching that
         * of the {@link #setSourceRect(Rect) source area} will be created to place the result.
             * Specifies the output bitmap in which to store the result. By default, a Bitmap of
             * format {@link android.graphics.Bitmap.Config#ARGB_8888} with a width & height
             * matching that of the {@link #setSourceRect(Rect) source area} will be created to
             * place the result.
             *
             * @param destination The bitmap to store the result, or null to have a bitmap
         *                    automatically created of the appropriate size. If not null, must not
         *                    be {@link Bitmap#isRecycled() recycled} and must be
             *                    automatically created of the appropriate size. If not null, must
             *                    not be {@link Bitmap#isRecycled() recycled} and must be
             *                    {@link Bitmap#isMutable() mutable}.
             * @return this
             */
        public @NonNull Request setDestinationBitmap(@Nullable Bitmap destination) {
            public @NonNull Builder setDestinationBitmap(@Nullable Bitmap destination) {
                requireNotBuilt();
                if (destination != null) {
                    validateBitmapDest(destination);
                }
            this.mDest = destination;
                mRequest.mDest = destination;
                return this;
            }

            /**
         * Executes the request.
             * @return The built {@link PixelCopy.Request}
             */
        public void request() {
            if (!mSource.isValid()) {
                mListenerThread.execute(() -> mListener.accept(
                        new CopyResult(ERROR_SOURCE_INVALID, null)));
                return;
            }
            HardwareRenderer.copySurfaceInto(mSource, new HardwareRenderer.CopyRequest(
                    adjustSourceRectForInsets(mSourceInsets, mSrcRect), mDest) {
                @Override
                public void onCopyFinished(int result) {
                    mListenerThread.execute(() -> mListener.accept(
                            new CopyResult(result, mDestinationBitmap)));
                }
            });
            public @NonNull Request build() {
                requireNotBuilt();
                Request ret = mRequest;
                mRequest = null;
                return ret;
            }
        }

@@ -427,33 +443,33 @@ public final class PixelCopy {
         * @param source The Window to copy from
         * @param callbackExecutor The executor to run the callback on
         * @param listener The callback for when the copy request is completed
     * @return A {@link Request} builder to set the optional params & execute the request
         * @return A {@link Builder} builder to set the optional params & execute the request
         */
    public static @NonNull Request ofWindow(@NonNull Window source,
        public static @NonNull Builder ofWindow(@NonNull Window source,
                                                @NonNull Executor callbackExecutor,
                                            @NonNull Consumer<CopyResult> listener) {
                                                @NonNull Consumer<Result> listener) {
            final Rect insets = new Rect();
            final Surface surface = sourceForWindow(source, insets);
        return new Request(surface, insets, callbackExecutor, listener);
            return new Builder(new Request(surface, insets, callbackExecutor, listener));
        }

        /**
         * Creates a PixelCopy request for the {@link Window} that the given {@link View} is
         * attached to.
         *
     * Note that this copy request is not cropped to the area the View occupies by default. If that
     * behavior is desired, use {@link View#getLocationInWindow(int[])} combined with
     * {@link Request#setSourceRect(Rect)} to set a crop area to restrict the copy operation.
         * Note that this copy request is not cropped to the area the View occupies by default. If
         * that behavior is desired, use {@link View#getLocationInWindow(int[])} combined with
         * {@link Builder#setSourceRect(Rect)} to set a crop area to restrict the copy operation.
         *
         * @param source A View that {@link View#isAttachedToWindow() is attached} to a window that
         *               will be used to retrieve the window to copy from.
         * @param callbackExecutor The executor to run the callback on
         * @param listener The callback for when the copy request is completed
     * @return A {@link Request} builder to set the optional params & execute the request
         * @return A {@link Builder} builder to set the optional params & execute the request
         */
    public static @NonNull Request ofWindow(@NonNull View source,
        public static @NonNull Builder ofWindow(@NonNull View source,
                                                @NonNull Executor callbackExecutor,
                                            @NonNull Consumer<CopyResult> listener) {
                                                @NonNull Consumer<Result> listener) {
            if (source == null || !source.isAttachedToWindow()) {
                throw new IllegalArgumentException(
                        "View must not be null & must be attached to window");
@@ -469,7 +485,7 @@ public final class PixelCopy {
                throw new IllegalArgumentException(
                        "Window doesn't have a backing surface!");
            }
        return new Request(surface, insets, callbackExecutor, listener);
            return new Builder(new Request(surface, insets, callbackExecutor, listener));
        }

        /**
@@ -478,15 +494,15 @@ public final class PixelCopy {
         * @param source The Surface to copy from. Must be {@link Surface#isValid() valid}.
         * @param callbackExecutor The executor to run the callback on
         * @param listener The callback for when the copy request is completed
     * @return A {@link Request} builder to set the optional params & execute the request
         * @return A {@link Builder} builder to set the optional params & execute the request
         */
    public static @NonNull Request ofSurface(@NonNull Surface source,
        public static @NonNull Builder ofSurface(@NonNull Surface source,
                                                 @NonNull Executor callbackExecutor,
                                             @NonNull Consumer<CopyResult> listener) {
                                                 @NonNull Consumer<Result> listener) {
            if (source == null || !source.isValid()) {
                throw new IllegalArgumentException("Source must not be null & must be valid");
            }
        return new Request(source, null, callbackExecutor, listener);
            return new Builder(new Request(source, null, callbackExecutor, listener));
        }

        /**
@@ -497,13 +513,55 @@ public final class PixelCopy {
         *               {@link Surface#isValid() valid}
         * @param callbackExecutor The executor to run the callback on
         * @param listener The callback for when the copy request is completed
     * @return A {@link Request} builder to set the optional params & execute the request
         * @return A {@link Builder} builder to set the optional params & execute the request
         */
    public static @NonNull Request ofSurface(@NonNull SurfaceView source,
        public static @NonNull Builder ofSurface(@NonNull SurfaceView source,
                                                 @NonNull Executor callbackExecutor,
                                             @NonNull Consumer<CopyResult> listener) {
                                                 @NonNull Consumer<Result> listener) {
            return ofSurface(source.getHolder().getSurface(), callbackExecutor, listener);
        }

        /**
         * @return The destination bitmap as set by {@link Builder#setDestinationBitmap(Bitmap)}
         */
        public @Nullable Bitmap getDestinationBitmap() {
            return mDest;
        }

        /**
         * @return The source rect to copy from as set by {@link Builder#setSourceRect(Rect)}
         */
        public @Nullable Rect getSourceRect() {
            return mSrcRect;
        }

        /**
         * @hide
         */
        public void request() {
            if (!mSource.isValid()) {
                mListenerThread.execute(() -> mListener.accept(
                        new Result(ERROR_SOURCE_INVALID, null)));
                return;
            }
            HardwareRenderer.copySurfaceInto(mSource, new HardwareRenderer.CopyRequest(
                    adjustSourceRectForInsets(mSourceInsets, mSrcRect), mDest) {
                @Override
                public void onCopyFinished(int result) {
                    mListenerThread.execute(() -> mListener.accept(
                            new Result(result, mDestinationBitmap)));
                }
            });
        }
    }

    /**
     * Executes the pixel copy request
     * @param request The request to execute
     */
    public static void request(@NonNull Request request) {
        request.request();
    }

    private PixelCopy() {}
}