• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 package com.android.systemui.screenshot;
17 
18 import static android.graphics.ColorSpace.Named.SRGB;
19 
20 import static java.util.Objects.requireNonNull;
21 
22 import android.annotation.NonNull;
23 import android.graphics.Bitmap;
24 import android.graphics.ColorSpace;
25 import android.graphics.RecordingCanvas;
26 import android.graphics.Rect;
27 import android.graphics.RenderNode;
28 import android.media.Image;
29 
30 /**
31  * Holds a hardware image, coordinates and render node to draw the tile. The tile manages clipping
32  * and dimensions. The tile must be drawn translated to the correct target position:
33  * <pre>
34  *     ImageTile tile = getTile();
35  *     canvas.save();
36  *     canvas.translate(tile.getLeft(), tile.getTop());
37  *     canvas.drawRenderNode(tile.getDisplayList());
38  *     canvas.restore();
39  * </pre>
40  */
41 class ImageTile implements AutoCloseable {
42     private final Image mImage;
43     private final Rect mLocation;
44     private RenderNode mNode;
45 
46     private static final ColorSpace COLOR_SPACE = ColorSpace.get(SRGB);
47 
48     /**
49      * Create an image tile from the given image.
50      *
51      * @param image an image containing a hardware buffer
52      * @param location the captured area represented by image tile (virtual coordinates)
53      */
ImageTile(@onNull Image image, @NonNull Rect location)54     ImageTile(@NonNull Image image, @NonNull Rect location) {
55         mImage = requireNonNull(image, "image");
56         mLocation = requireNonNull(location);
57         requireNonNull(mImage.getHardwareBuffer(), "image must be a hardware image");
58     }
59 
getDisplayList()60     synchronized RenderNode getDisplayList() {
61         if (mNode == null) {
62             mNode = new RenderNode("Tile{" + Integer.toHexString(mImage.hashCode()) + "}");
63         }
64         if (mNode.hasDisplayList()) {
65             return mNode;
66         }
67         final int w = Math.min(mImage.getWidth(), mLocation.width());
68         final int h = Math.min(mImage.getHeight(), mLocation.height());
69         mNode.setPosition(0, 0, w, h);
70 
71         RecordingCanvas canvas = mNode.beginRecording(w, h);
72         canvas.save();
73         canvas.clipRect(0, 0, mLocation.width(), mLocation.height());
74         canvas.drawBitmap(Bitmap.wrapHardwareBuffer(mImage.getHardwareBuffer(), COLOR_SPACE),
75                 0, 0, null);
76         canvas.restore();
77         mNode.endRecording();
78         return mNode;
79     }
80 
getLocation()81     Rect getLocation() {
82         return mLocation;
83     }
84 
getLeft()85     int getLeft() {
86         return mLocation.left;
87     }
88 
getTop()89     int getTop() {
90         return mLocation.top;
91     }
92 
getRight()93     int getRight() {
94         return mLocation.right;
95     }
96 
getBottom()97     int getBottom() {
98         return mLocation.bottom;
99     }
100 
101     @Override
close()102     public synchronized void close() {
103         mImage.close();
104         if (mNode != null) {
105             mNode.discardDisplayList();
106         }
107     }
108 
109     @Override
toString()110     public String toString() {
111         return "{location=" + mLocation + ", source=" + mImage
112                 + ", buffer=" + mImage.getHardwareBuffer() + "}";
113     }
114 }
115