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