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