1 /*
2  * Copyright (C) 2022 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.window;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.graphics.Bitmap;
22 import android.graphics.ColorSpace;
23 import android.graphics.PixelFormat;
24 import android.graphics.Rect;
25 import android.hardware.HardwareBuffer;
26 import android.os.IBinder;
27 import android.os.Parcel;
28 import android.os.Parcelable;
29 import android.util.Log;
30 import android.view.SurfaceControl;
31 
32 import libcore.util.NativeAllocationRegistry;
33 
34 import java.util.concurrent.CountDownLatch;
35 import java.util.concurrent.TimeUnit;
36 import java.util.function.Consumer;
37 
38 /**
39  * Handles display and layer captures for the system.
40  *
41  * @hide
42  */
43 public class ScreenCapture {
44     private static final String TAG = "ScreenCapture";
45     private static final int SCREENSHOT_WAIT_TIME_S = 1;
46 
nativeCaptureDisplay(DisplayCaptureArgs captureArgs, long captureListener)47     private static native int nativeCaptureDisplay(DisplayCaptureArgs captureArgs,
48             long captureListener);
nativeCaptureLayers(LayerCaptureArgs captureArgs, long captureListener)49     private static native int nativeCaptureLayers(LayerCaptureArgs captureArgs,
50             long captureListener);
nativeCreateScreenCaptureListener( Consumer<ScreenshotHardwareBuffer> consumer)51     private static native long nativeCreateScreenCaptureListener(
52             Consumer<ScreenshotHardwareBuffer> consumer);
nativeWriteListenerToParcel(long nativeObject, Parcel out)53     private static native void nativeWriteListenerToParcel(long nativeObject, Parcel out);
nativeReadListenerFromParcel(Parcel in)54     private static native long nativeReadListenerFromParcel(Parcel in);
getNativeListenerFinalizer()55     private static native long getNativeListenerFinalizer();
56 
57     /**
58      * @param captureArgs     Arguments about how to take the screenshot
59      * @param captureListener A listener to receive the screenshot callback
60      * @hide
61      */
captureDisplay(@onNull DisplayCaptureArgs captureArgs, @NonNull ScreenCaptureListener captureListener)62     public static int captureDisplay(@NonNull DisplayCaptureArgs captureArgs,
63             @NonNull ScreenCaptureListener captureListener) {
64         return nativeCaptureDisplay(captureArgs, captureListener.mNativeObject);
65     }
66 
67     /**
68      * Captures all the surfaces in a display and returns a {@link ScreenshotHardwareBuffer} with
69      * the content.
70      *
71      * @hide
72      */
captureDisplay( DisplayCaptureArgs captureArgs)73     public static ScreenshotHardwareBuffer captureDisplay(
74             DisplayCaptureArgs captureArgs) {
75         SynchronousScreenCaptureListener syncScreenCapture = createSyncCaptureListener();
76         int status = captureDisplay(captureArgs, syncScreenCapture);
77         if (status != 0) {
78             return null;
79         }
80 
81         try {
82             return syncScreenCapture.getBuffer();
83         } catch (Exception e) {
84             return null;
85         }
86     }
87 
88     /**
89      * Captures a layer and its children and returns a {@link HardwareBuffer} with the content.
90      *
91      * @param layer      The root layer to capture.
92      * @param sourceCrop The portion of the root surface to capture; caller may pass in 'new
93      *                   Rect()' or null if no cropping is desired. If the root layer does not
94      *                   have a buffer or a crop set, then a non-empty source crop must be
95      *                   specified.
96      * @param frameScale The desired scale of the returned buffer; the raw screen will be scaled
97      *                   up/down.
98      * @return Returns a HardwareBuffer that contains the layer capture.
99      * @hide
100      */
captureLayers(SurfaceControl layer, Rect sourceCrop, float frameScale)101     public static ScreenshotHardwareBuffer captureLayers(SurfaceControl layer, Rect sourceCrop,
102             float frameScale) {
103         return captureLayers(layer, sourceCrop, frameScale, PixelFormat.RGBA_8888);
104     }
105 
106     /**
107      * Captures a layer and its children and returns a {@link HardwareBuffer} with the content.
108      *
109      * @param layer      The root layer to capture.
110      * @param sourceCrop The portion of the root surface to capture; caller may pass in 'new
111      *                   Rect()' or null if no cropping is desired. If the root layer does not
112      *                   have a buffer or a crop set, then a non-empty source crop must be
113      *                   specified.
114      * @param frameScale The desired scale of the returned buffer; the raw screen will be scaled
115      *                   up/down.
116      * @param format     The desired pixel format of the returned buffer.
117      * @return Returns a HardwareBuffer that contains the layer capture.
118      * @hide
119      */
captureLayers(@onNull SurfaceControl layer, @Nullable Rect sourceCrop, float frameScale, int format)120     public static ScreenshotHardwareBuffer captureLayers(@NonNull SurfaceControl layer,
121             @Nullable Rect sourceCrop, float frameScale, int format) {
122         LayerCaptureArgs captureArgs = new LayerCaptureArgs.Builder(layer)
123                 .setSourceCrop(sourceCrop)
124                 .setFrameScale(frameScale)
125                 .setPixelFormat(format)
126                 .build();
127 
128         return captureLayers(captureArgs);
129     }
130 
131     /**
132      * @hide
133      */
captureLayers(LayerCaptureArgs captureArgs)134     public static ScreenshotHardwareBuffer captureLayers(LayerCaptureArgs captureArgs) {
135         SynchronousScreenCaptureListener syncScreenCapture = createSyncCaptureListener();
136         int status = captureLayers(captureArgs, syncScreenCapture);
137         if (status != 0) {
138             return null;
139         }
140 
141         try {
142             return syncScreenCapture.getBuffer();
143         } catch (Exception e) {
144             return null;
145         }
146     }
147 
148     /**
149      * Like {@link #captureLayers(SurfaceControl, Rect, float, int)} but with an array of layer
150      * handles to exclude.
151      *
152      * @hide
153      */
captureLayersExcluding(SurfaceControl layer, Rect sourceCrop, float frameScale, int format, SurfaceControl[] exclude)154     public static ScreenshotHardwareBuffer captureLayersExcluding(SurfaceControl layer,
155             Rect sourceCrop, float frameScale, int format, SurfaceControl[] exclude) {
156         LayerCaptureArgs captureArgs = new LayerCaptureArgs.Builder(layer)
157                 .setSourceCrop(sourceCrop)
158                 .setFrameScale(frameScale)
159                 .setPixelFormat(format)
160                 .setExcludeLayers(exclude)
161                 .build();
162 
163         return captureLayers(captureArgs);
164     }
165 
166     /**
167      * @param captureArgs     Arguments about how to take the screenshot
168      * @param captureListener A listener to receive the screenshot callback
169      * @hide
170      */
captureLayers(@onNull LayerCaptureArgs captureArgs, @NonNull ScreenCaptureListener captureListener)171     public static int captureLayers(@NonNull LayerCaptureArgs captureArgs,
172             @NonNull ScreenCaptureListener captureListener) {
173         return nativeCaptureLayers(captureArgs, captureListener.mNativeObject);
174     }
175 
176     /**
177      * A wrapper around HardwareBuffer that contains extra information about how to
178      * interpret the screenshot HardwareBuffer.
179      *
180      * @hide
181      */
182     public static class ScreenshotHardwareBuffer {
183         private final HardwareBuffer mHardwareBuffer;
184         private final ColorSpace mColorSpace;
185         private final boolean mContainsSecureLayers;
186         private final boolean mContainsHdrLayers;
187 
ScreenshotHardwareBuffer(HardwareBuffer hardwareBuffer, ColorSpace colorSpace, boolean containsSecureLayers, boolean containsHdrLayers)188         public ScreenshotHardwareBuffer(HardwareBuffer hardwareBuffer, ColorSpace colorSpace,
189                 boolean containsSecureLayers, boolean containsHdrLayers) {
190             mHardwareBuffer = hardwareBuffer;
191             mColorSpace = colorSpace;
192             mContainsSecureLayers = containsSecureLayers;
193             mContainsHdrLayers = containsHdrLayers;
194         }
195 
196         /**
197          * Create ScreenshotHardwareBuffer from an existing HardwareBuffer object.
198          *
199          * @param hardwareBuffer       The existing HardwareBuffer object
200          * @param dataspace            Dataspace describing the content.
201          *                             {@see android.hardware.DataSpace}
202          * @param containsSecureLayers Indicates whether this graphic buffer contains captured
203          *                             contents of secure layers, in which case the screenshot
204          *                             should not be persisted.
205          * @param containsHdrLayers    Indicates whether this graphic buffer contains HDR content.
206          */
createFromNative(HardwareBuffer hardwareBuffer, int dataspace, boolean containsSecureLayers, boolean containsHdrLayers)207         private static ScreenshotHardwareBuffer createFromNative(HardwareBuffer hardwareBuffer,
208                 int dataspace, boolean containsSecureLayers, boolean containsHdrLayers) {
209             ColorSpace colorSpace = ColorSpace.getFromDataSpace(dataspace);
210             return new ScreenshotHardwareBuffer(
211                     hardwareBuffer,
212                     colorSpace != null ? colorSpace : ColorSpace.get(ColorSpace.Named.SRGB),
213                     containsSecureLayers,
214                     containsHdrLayers);
215         }
216 
getColorSpace()217         public ColorSpace getColorSpace() {
218             return mColorSpace;
219         }
220 
getHardwareBuffer()221         public HardwareBuffer getHardwareBuffer() {
222             return mHardwareBuffer;
223         }
224 
225         /**
226          * Whether this screenshot contains secure layers
227          */
containsSecureLayers()228         public boolean containsSecureLayers() {
229             return mContainsSecureLayers;
230         }
231 
232         /**
233          * Returns whether the screenshot contains at least one HDR layer.
234          * This information may be useful for informing the display whether this screenshot
235          * is allowed to be dimmed to SDR white.
236          */
containsHdrLayers()237         public boolean containsHdrLayers() {
238             return mContainsHdrLayers;
239         }
240 
241         /**
242          * Copy content of ScreenshotHardwareBuffer into a hardware bitmap and return it.
243          * Note: If you want to modify the Bitmap in software, you will need to copy the Bitmap
244          * into
245          * a software Bitmap using {@link Bitmap#copy(Bitmap.Config, boolean)}
246          * <p>
247          * CAVEAT: This can be extremely slow; avoid use unless absolutely necessary; prefer to
248          * directly
249          * use the {@link HardwareBuffer} directly.
250          *
251          * @return Bitmap generated from the {@link HardwareBuffer}
252          */
asBitmap()253         public Bitmap asBitmap() {
254             if (mHardwareBuffer == null) {
255                 Log.w(TAG, "Failed to take screenshot. Null screenshot object");
256                 return null;
257             }
258             return Bitmap.wrapHardwareBuffer(mHardwareBuffer, mColorSpace);
259         }
260     }
261 
262     /**
263      * A common arguments class used for various screenshot requests. This contains arguments that
264      * are shared between {@link DisplayCaptureArgs} and {@link LayerCaptureArgs}
265      *
266      * @hide
267      */
268     public static class CaptureArgs implements Parcelable {
269         public final int mPixelFormat;
270         public final Rect mSourceCrop = new Rect();
271         public final float mFrameScaleX;
272         public final float mFrameScaleY;
273         public final boolean mCaptureSecureLayers;
274         public final boolean mAllowProtected;
275         public final long mUid;
276         public final boolean mGrayscale;
277         final SurfaceControl[] mExcludeLayers;
278         public final boolean mHintForSeamlessTransition;
279 
CaptureArgs(CaptureArgs.Builder<? extends CaptureArgs.Builder<?>> builder)280         private CaptureArgs(CaptureArgs.Builder<? extends CaptureArgs.Builder<?>> builder) {
281             mPixelFormat = builder.mPixelFormat;
282             mSourceCrop.set(builder.mSourceCrop);
283             mFrameScaleX = builder.mFrameScaleX;
284             mFrameScaleY = builder.mFrameScaleY;
285             mCaptureSecureLayers = builder.mCaptureSecureLayers;
286             mAllowProtected = builder.mAllowProtected;
287             mUid = builder.mUid;
288             mGrayscale = builder.mGrayscale;
289             mExcludeLayers = builder.mExcludeLayers;
290             mHintForSeamlessTransition = builder.mHintForSeamlessTransition;
291         }
292 
CaptureArgs(Parcel in)293         private CaptureArgs(Parcel in) {
294             mPixelFormat = in.readInt();
295             mSourceCrop.readFromParcel(in);
296             mFrameScaleX = in.readFloat();
297             mFrameScaleY = in.readFloat();
298             mCaptureSecureLayers = in.readBoolean();
299             mAllowProtected = in.readBoolean();
300             mUid = in.readLong();
301             mGrayscale = in.readBoolean();
302 
303             int excludeLayersLength = in.readInt();
304             if (excludeLayersLength > 0) {
305                 mExcludeLayers = new SurfaceControl[excludeLayersLength];
306                 for (int index = 0; index < excludeLayersLength; index++) {
307                     mExcludeLayers[index] = SurfaceControl.CREATOR.createFromParcel(in);
308                 }
309             } else {
310                 mExcludeLayers = null;
311             }
312             mHintForSeamlessTransition = in.readBoolean();
313         }
314 
315         /** Release any layers if set using {@link Builder#setExcludeLayers(SurfaceControl[])}. */
release()316         public void release() {
317             if (mExcludeLayers == null || mExcludeLayers.length == 0) {
318                 return;
319             }
320 
321             for (SurfaceControl surfaceControl : mExcludeLayers) {
322                 if (surfaceControl != null) {
323                     surfaceControl.release();
324                 }
325             }
326         }
327 
328         /**
329          * Returns an array of {@link SurfaceControl#mNativeObject} corresponding to
330          * {@link #mExcludeLayers}. Used only in native code.
331          */
getNativeExcludeLayers()332         private long[] getNativeExcludeLayers() {
333             if (mExcludeLayers == null || mExcludeLayers.length == 0) {
334                 return new long[0];
335             }
336 
337             long[] nativeExcludeLayers = new long[mExcludeLayers.length];
338             for (int index = 0; index < mExcludeLayers.length; index++) {
339                 nativeExcludeLayers[index] = mExcludeLayers[index].mNativeObject;
340             }
341 
342             return nativeExcludeLayers;
343         }
344 
345         /**
346          * The Builder class used to construct {@link CaptureArgs}
347          *
348          * @param <T> A builder that extends {@link CaptureArgs.Builder}
349          */
350         public static class Builder<T extends CaptureArgs.Builder<T>> {
351             private int mPixelFormat = PixelFormat.RGBA_8888;
352             private final Rect mSourceCrop = new Rect();
353             private float mFrameScaleX = 1;
354             private float mFrameScaleY = 1;
355             private boolean mCaptureSecureLayers;
356             private boolean mAllowProtected;
357             private long mUid = -1;
358             private boolean mGrayscale;
359             private SurfaceControl[] mExcludeLayers;
360             private boolean mHintForSeamlessTransition;
361 
362             /**
363              * Construct a new {@link CaptureArgs} with the set parameters. The builder remains
364              * valid.
365              */
build()366             public CaptureArgs build() {
367                 return new CaptureArgs(this);
368             }
369 
370             /**
371              * The desired pixel format of the returned buffer.
372              */
setPixelFormat(int pixelFormat)373             public T setPixelFormat(int pixelFormat) {
374                 mPixelFormat = pixelFormat;
375                 return getThis();
376             }
377 
378             /**
379              * The portion of the screen to capture into the buffer. Caller may pass  in
380              * 'new Rect()' or null if no cropping is desired.
381              */
setSourceCrop(@ullable Rect sourceCrop)382             public T setSourceCrop(@Nullable Rect sourceCrop) {
383                 if (sourceCrop == null) {
384                     mSourceCrop.setEmpty();
385                 } else {
386                     mSourceCrop.set(sourceCrop);
387                 }
388                 return getThis();
389             }
390 
391             /**
392              * The desired scale of the returned buffer. The raw screen will be scaled up/down.
393              */
setFrameScale(float frameScale)394             public T setFrameScale(float frameScale) {
395                 mFrameScaleX = frameScale;
396                 mFrameScaleY = frameScale;
397                 return getThis();
398             }
399 
400             /**
401              * The desired scale of the returned buffer, allowing separate values for x and y scale.
402              * The raw screen will be scaled up/down.
403              */
setFrameScale(float frameScaleX, float frameScaleY)404             public T setFrameScale(float frameScaleX, float frameScaleY) {
405                 mFrameScaleX = frameScaleX;
406                 mFrameScaleY = frameScaleY;
407                 return getThis();
408             }
409 
410             /**
411              * Whether to allow the screenshot of secure layers. Warning: This should only be done
412              * if the content will be placed in a secure SurfaceControl.
413              *
414              * @see ScreenshotHardwareBuffer#containsSecureLayers()
415              */
setCaptureSecureLayers(boolean captureSecureLayers)416             public T setCaptureSecureLayers(boolean captureSecureLayers) {
417                 mCaptureSecureLayers = captureSecureLayers;
418                 return getThis();
419             }
420 
421             /**
422              * Whether to allow the screenshot of protected (DRM) content. Warning: The screenshot
423              * cannot be read in unprotected space.
424              *
425              * @see HardwareBuffer#USAGE_PROTECTED_CONTENT
426              */
setAllowProtected(boolean allowProtected)427             public T setAllowProtected(boolean allowProtected) {
428                 mAllowProtected = allowProtected;
429                 return getThis();
430             }
431 
432             /**
433              * Set the uid of the content that should be screenshot. The code will skip any surfaces
434              * that don't belong to the specified uid.
435              */
setUid(long uid)436             public T setUid(long uid) {
437                 mUid = uid;
438                 return getThis();
439             }
440 
441             /**
442              * Set whether the screenshot should use grayscale or not.
443              */
setGrayscale(boolean grayscale)444             public T setGrayscale(boolean grayscale) {
445                 mGrayscale = grayscale;
446                 return getThis();
447             }
448 
449             /**
450              * An array of {@link SurfaceControl} layer handles to exclude.
451              */
setExcludeLayers(@ullable SurfaceControl[] excludeLayers)452             public T setExcludeLayers(@Nullable SurfaceControl[] excludeLayers) {
453                 mExcludeLayers = excludeLayers;
454                 return getThis();
455             }
456 
457             /**
458              * Set whether the screenshot will be used in a system animation.
459              * This hint is used for picking the "best" colorspace for the screenshot, in particular
460              * for mixing HDR and SDR content.
461              * E.g., hintForSeamlessTransition is false, then a colorspace suitable for file
462              * encoding, such as BT2100, may be chosen. Otherwise, then the display's color space
463              * would be chosen, with the possibility of having an extended brightness range. This
464              * is important for screenshots that are directly re-routed to a SurfaceControl in
465              * order to preserve accurate colors.
466              */
setHintForSeamlessTransition(boolean hintForSeamlessTransition)467             public T setHintForSeamlessTransition(boolean hintForSeamlessTransition) {
468                 mHintForSeamlessTransition = hintForSeamlessTransition;
469                 return getThis();
470             }
471 
472             /**
473              * Each sub class should return itself to allow the builder to chain properly
474              */
getThis()475             T getThis() {
476                 return (T) this;
477             }
478         }
479 
480         @Override
describeContents()481         public int describeContents() {
482             return 0;
483         }
484 
485         @Override
writeToParcel(@onNull Parcel dest, int flags)486         public void writeToParcel(@NonNull Parcel dest, int flags) {
487             dest.writeInt(mPixelFormat);
488             mSourceCrop.writeToParcel(dest, flags);
489             dest.writeFloat(mFrameScaleX);
490             dest.writeFloat(mFrameScaleY);
491             dest.writeBoolean(mCaptureSecureLayers);
492             dest.writeBoolean(mAllowProtected);
493             dest.writeLong(mUid);
494             dest.writeBoolean(mGrayscale);
495             if (mExcludeLayers != null) {
496                 dest.writeInt(mExcludeLayers.length);
497                 for (SurfaceControl excludeLayer : mExcludeLayers) {
498                     excludeLayer.writeToParcel(dest, flags);
499                 }
500             } else {
501                 dest.writeInt(0);
502             }
503             dest.writeBoolean(mHintForSeamlessTransition);
504         }
505 
506         public static final Parcelable.Creator<CaptureArgs> CREATOR =
507                 new Parcelable.Creator<CaptureArgs>() {
508                     @Override
509                     public CaptureArgs createFromParcel(Parcel in) {
510                         return new CaptureArgs(in);
511                     }
512 
513                     @Override
514                     public CaptureArgs[] newArray(int size) {
515                         return new CaptureArgs[size];
516                     }
517                 };
518     }
519 
520     /**
521      * The arguments class used to make display capture requests.
522      *
523      * @hide
524      * @see #nativeCaptureDisplay(DisplayCaptureArgs, long)
525      */
526     public static class DisplayCaptureArgs extends CaptureArgs {
527         private final IBinder mDisplayToken;
528         private final int mWidth;
529         private final int mHeight;
530         private final boolean mUseIdentityTransform;
531 
DisplayCaptureArgs(Builder builder)532         private DisplayCaptureArgs(Builder builder) {
533             super(builder);
534             mDisplayToken = builder.mDisplayToken;
535             mWidth = builder.mWidth;
536             mHeight = builder.mHeight;
537             mUseIdentityTransform = builder.mUseIdentityTransform;
538         }
539 
540         /**
541          * The Builder class used to construct {@link DisplayCaptureArgs}
542          */
543         public static class Builder extends CaptureArgs.Builder<Builder> {
544             private IBinder mDisplayToken;
545             private int mWidth;
546             private int mHeight;
547             private boolean mUseIdentityTransform;
548 
549             /**
550              * Construct a new {@link LayerCaptureArgs} with the set parameters. The builder
551              * remains valid.
552              */
build()553             public DisplayCaptureArgs build() {
554                 if (mDisplayToken == null) {
555                     throw new IllegalStateException(
556                             "Can't take screenshot with null display token");
557                 }
558                 return new DisplayCaptureArgs(this);
559             }
560 
Builder(IBinder displayToken)561             public Builder(IBinder displayToken) {
562                 setDisplayToken(displayToken);
563             }
564 
565             /**
566              * The display to take the screenshot of.
567              */
setDisplayToken(IBinder displayToken)568             public Builder setDisplayToken(IBinder displayToken) {
569                 mDisplayToken = displayToken;
570                 return this;
571             }
572 
573             /**
574              * Set the desired size of the returned buffer. The raw screen  will be  scaled down to
575              * this size
576              *
577              * @param width  The desired width of the returned buffer. Caller may pass in 0 if no
578              *               scaling is desired.
579              * @param height The desired height of the returned buffer. Caller may pass in 0 if no
580              *               scaling is desired.
581              */
setSize(int width, int height)582             public Builder setSize(int width, int height) {
583                 mWidth = width;
584                 mHeight = height;
585                 return this;
586             }
587 
588             /**
589              * Replace the rotation transform of the display with the identity transformation while
590              * taking the screenshot. This ensures the screenshot is taken in the ROTATION_0
591              * orientation. Set this value to false if the screenshot should be taken in the
592              * current screen orientation.
593              */
setUseIdentityTransform(boolean useIdentityTransform)594             public Builder setUseIdentityTransform(boolean useIdentityTransform) {
595                 mUseIdentityTransform = useIdentityTransform;
596                 return this;
597             }
598 
599             @Override
getThis()600             Builder getThis() {
601                 return this;
602             }
603         }
604     }
605 
606     /**
607      * The arguments class used to make layer capture requests.
608      *
609      * @hide
610      * @see #nativeCaptureLayers(LayerCaptureArgs, long)
611      */
612     public static class LayerCaptureArgs extends CaptureArgs {
613         private final long mNativeLayer;
614         private final boolean mChildrenOnly;
615 
LayerCaptureArgs(Builder builder)616         private LayerCaptureArgs(Builder builder) {
617             super(builder);
618             mChildrenOnly = builder.mChildrenOnly;
619             mNativeLayer = builder.mLayer.mNativeObject;
620         }
621 
622         /**
623          * The Builder class used to construct {@link LayerCaptureArgs}
624          */
625         public static class Builder extends CaptureArgs.Builder<Builder> {
626             private SurfaceControl mLayer;
627             private boolean mChildrenOnly = true;
628 
629             /**
630              * Construct a new {@link LayerCaptureArgs} with the set parameters. The builder
631              * remains valid.
632              */
build()633             public LayerCaptureArgs build() {
634                 if (mLayer == null) {
635                     throw new IllegalStateException(
636                             "Can't take screenshot with null layer");
637                 }
638                 return new LayerCaptureArgs(this);
639             }
640 
Builder(SurfaceControl layer, CaptureArgs args)641             public Builder(SurfaceControl layer, CaptureArgs args) {
642                 setLayer(layer);
643                 setPixelFormat(args.mPixelFormat);
644                 setSourceCrop(args.mSourceCrop);
645                 setFrameScale(args.mFrameScaleX, args.mFrameScaleY);
646                 setCaptureSecureLayers(args.mCaptureSecureLayers);
647                 setAllowProtected(args.mAllowProtected);
648                 setUid(args.mUid);
649                 setGrayscale(args.mGrayscale);
650                 setExcludeLayers(args.mExcludeLayers);
651                 setHintForSeamlessTransition(args.mHintForSeamlessTransition);
652             }
653 
Builder(SurfaceControl layer)654             public Builder(SurfaceControl layer) {
655                 setLayer(layer);
656             }
657 
658             /**
659              * The root layer to capture.
660              */
setLayer(SurfaceControl layer)661             public Builder setLayer(SurfaceControl layer) {
662                 mLayer = layer;
663                 return this;
664             }
665 
666             /**
667              * Whether to include the layer itself in the screenshot or just the children and their
668              * descendants.
669              */
setChildrenOnly(boolean childrenOnly)670             public Builder setChildrenOnly(boolean childrenOnly) {
671                 mChildrenOnly = childrenOnly;
672                 return this;
673             }
674 
675             @Override
getThis()676             Builder getThis() {
677                 return this;
678             }
679         }
680     }
681 
682     /**
683      * The object used to receive the results when invoking screen capture requests via
684      * {@link #captureDisplay(DisplayCaptureArgs, ScreenCaptureListener)} or
685      * {@link #captureLayers(LayerCaptureArgs, ScreenCaptureListener)}
686      *
687      * This listener can only be used for a single call to capture content call.
688      */
689     public static class ScreenCaptureListener implements Parcelable {
690         private final long mNativeObject;
691         private static final NativeAllocationRegistry sRegistry =
692                 NativeAllocationRegistry.createMalloced(
693                         ScreenCaptureListener.class.getClassLoader(), getNativeListenerFinalizer());
694 
695         /**
696          * @param consumer The callback invoked when the screen capture is complete.
697          */
ScreenCaptureListener(Consumer<ScreenshotHardwareBuffer> consumer)698         public ScreenCaptureListener(Consumer<ScreenshotHardwareBuffer> consumer) {
699             mNativeObject = nativeCreateScreenCaptureListener(consumer);
700             sRegistry.registerNativeAllocation(this, mNativeObject);
701         }
702 
ScreenCaptureListener(Parcel in)703         private ScreenCaptureListener(Parcel in) {
704             if (in.readBoolean()) {
705                 mNativeObject = nativeReadListenerFromParcel(in);
706                 sRegistry.registerNativeAllocation(this, mNativeObject);
707             } else {
708                 mNativeObject = 0;
709             }
710         }
711 
712         @Override
describeContents()713         public int describeContents() {
714             return 0;
715         }
716 
717         @Override
writeToParcel(@onNull Parcel dest, int flags)718         public void writeToParcel(@NonNull Parcel dest, int flags) {
719             if (mNativeObject == 0) {
720                 dest.writeBoolean(false);
721             } else {
722                 dest.writeBoolean(true);
723                 nativeWriteListenerToParcel(mNativeObject, dest);
724             }
725         }
726 
727         public static final Parcelable.Creator<ScreenCaptureListener> CREATOR =
728                 new Parcelable.Creator<ScreenCaptureListener>() {
729                     @Override
730                     public ScreenCaptureListener createFromParcel(Parcel in) {
731                         return new ScreenCaptureListener(in);
732                     }
733 
734                     @Override
735                     public ScreenCaptureListener[] newArray(int size) {
736                         return new ScreenCaptureListener[0];
737                     }
738                 };
739     }
740 
741     /**
742      * A helper method to handle the async screencapture callbacks synchronously. This should only
743      * be used if the screencapture caller doesn't care that it blocks waiting for a screenshot.
744      *
745      * @return a {@link SynchronousScreenCaptureListener} that should be used for capture
746      * calls into SurfaceFlinger.
747      */
createSyncCaptureListener()748     public static SynchronousScreenCaptureListener createSyncCaptureListener() {
749         ScreenshotHardwareBuffer[] bufferRef = new ScreenshotHardwareBuffer[1];
750         CountDownLatch latch = new CountDownLatch(1);
751         Consumer<ScreenshotHardwareBuffer> consumer = buffer -> {
752             bufferRef[0] = buffer;
753             latch.countDown();
754         };
755 
756         return new SynchronousScreenCaptureListener(consumer) {
757             // In order to avoid requiring two GC cycles to clean up the consumer and the buffer
758             // it references, the underlying JNI listener holds a weak reference to the consumer.
759             // This property exists to ensure the consumer stays alive during the listener's
760             // lifetime.
761             private Consumer<ScreenshotHardwareBuffer> mConsumer = consumer;
762 
763             @Override
764             public ScreenshotHardwareBuffer getBuffer() {
765                 try {
766                     latch.await(SCREENSHOT_WAIT_TIME_S, TimeUnit.SECONDS);
767                     return bufferRef[0];
768                 } catch (Exception e) {
769                     Log.e(TAG, "Failed to wait for screen capture result", e);
770                     return null;
771                 }
772             }
773         };
774     }
775 
776     /**
777      * Helper class to synchronously get the {@link ScreenshotHardwareBuffer} when calling
778      * {@link #captureLayers(LayerCaptureArgs, ScreenCaptureListener)} or
779      * {@link #captureDisplay(DisplayCaptureArgs, ScreenCaptureListener)}
780      */
781     public abstract static class SynchronousScreenCaptureListener extends ScreenCaptureListener {
SynchronousScreenCaptureListener(Consumer<ScreenshotHardwareBuffer> consumer)782         SynchronousScreenCaptureListener(Consumer<ScreenshotHardwareBuffer> consumer) {
783             super(consumer);
784         }
785 
786         /**
787          * Get the {@link ScreenshotHardwareBuffer} synchronously. This can be null if the
788          * screenshot failed or if there was no callback in {@link #SCREENSHOT_WAIT_TIME_S} seconds.
789          */
getBuffer()790         public abstract ScreenshotHardwareBuffer getBuffer();
791     }
792 }
793