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