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