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