1 /*
2  * Copyright (C) 2021 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 com.android.wm.shell.common;
18 
19 import android.graphics.GraphicBuffer;
20 import android.graphics.PixelFormat;
21 import android.graphics.Rect;
22 import android.view.SurfaceControl;
23 
24 import java.util.function.Consumer;
25 
26 /**
27  * Helpers for working with screenshots.
28  */
29 public class ScreenshotUtils {
30 
31     /**
32      * Take a screenshot of the specified SurfaceControl.
33      *
34      * @param sc the SurfaceControl to take a screenshot of
35      * @param crop the crop to use when capturing the screenshot
36      * @param consumer Consumer for the captured buffer
37      */
captureLayer(SurfaceControl sc, Rect crop, Consumer<SurfaceControl.ScreenshotHardwareBuffer> consumer)38     public static void captureLayer(SurfaceControl sc, Rect crop,
39             Consumer<SurfaceControl.ScreenshotHardwareBuffer> consumer) {
40         consumer.accept(SurfaceControl.captureLayers(
41                 new SurfaceControl.LayerCaptureArgs.Builder(sc)
42                     .setSourceCrop(crop)
43                     .setCaptureSecureLayers(true)
44                     .setAllowProtected(true)
45                     .build()));
46     }
47 
48     private static class BufferConsumer implements
49             Consumer<SurfaceControl.ScreenshotHardwareBuffer> {
50         SurfaceControl mScreenshot = null;
51         SurfaceControl.Transaction mTransaction;
52         SurfaceControl mSurfaceControl;
53         int mLayer;
54 
BufferConsumer(SurfaceControl.Transaction t, SurfaceControl sc, int layer)55         BufferConsumer(SurfaceControl.Transaction t, SurfaceControl sc, int layer) {
56             mTransaction = t;
57             mSurfaceControl = sc;
58             mLayer = layer;
59         }
60 
61         @Override
accept(SurfaceControl.ScreenshotHardwareBuffer buffer)62         public void accept(SurfaceControl.ScreenshotHardwareBuffer buffer) {
63             if (buffer == null || buffer.getHardwareBuffer() == null) {
64                 return;
65             }
66             final GraphicBuffer graphicBuffer = GraphicBuffer.createFromHardwareBuffer(
67                 buffer.getHardwareBuffer());
68             mScreenshot = new SurfaceControl.Builder()
69                 .setName("ScreenshotUtils screenshot")
70                 .setFormat(PixelFormat.TRANSLUCENT)
71                 .setSecure(buffer.containsSecureLayers())
72                 .setCallsite("ScreenshotUtils.takeScreenshot")
73                 .setBLASTLayer()
74                 .build();
75 
76             mTransaction.setBuffer(mScreenshot, graphicBuffer);
77             mTransaction.setColorSpace(mScreenshot, buffer.getColorSpace());
78             mTransaction.reparent(mScreenshot, mSurfaceControl);
79             mTransaction.setLayer(mScreenshot, mLayer);
80             mTransaction.show(mScreenshot);
81             mTransaction.apply();
82         }
83     }
84 
85     /**
86      * Take a screenshot of the specified SurfaceControl.
87      *
88      * @param t the transaction used to set changes on the resulting screenshot.
89      * @param sc the SurfaceControl to take a screenshot of
90      * @param crop the crop to use when capturing the screenshot
91      * @param layer the layer to place the screenshot
92      *
93      * @return A SurfaceControl where the screenshot will be attached, or null if failed.
94      */
takeScreenshot(SurfaceControl.Transaction t, SurfaceControl sc, Rect crop, int layer)95     public static SurfaceControl takeScreenshot(SurfaceControl.Transaction t, SurfaceControl sc,
96             Rect crop, int layer) {
97         BufferConsumer consumer = new BufferConsumer(t, sc, layer);
98         captureLayer(sc, crop, consumer);
99         return consumer.mScreenshot;
100     }
101 }
102