blob: a95c91bfeceb325041681d0e1b858ba7fdab21a5 [file] [log] [blame]
/*
* Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.screenshot;
import static android.graphics.ColorSpace.Named.SRGB;
import static java.util.Objects.requireNonNull;
import android.annotation.NonNull;
import android.graphics.Bitmap;
import android.graphics.ColorSpace;
import android.graphics.RecordingCanvas;
import android.graphics.Rect;
import android.graphics.RenderNode;
import android.media.Image;
/**
* Holds a hardware image, coordinates and render node to draw the tile. The tile manages clipping
* and dimensions. The tile must be drawn translated to the correct target position:
* <pre>
* ImageTile tile = getTile();
* canvas.save();
* canvas.translate(tile.getLeft(), tile.getTop());
* canvas.drawRenderNode(tile.getDisplayList());
* canvas.restore();
* </pre>
*/
class ImageTile implements AutoCloseable {
private final Image mImage;
private final Rect mLocation;
private RenderNode mNode;
private static final ColorSpace COLOR_SPACE = ColorSpace.get(SRGB);
/**
* Create an image tile from the given image.
*
* @param image an image containing a hardware buffer
* @param location the captured area represented by image tile (virtual coordinates)
*/
ImageTile(@NonNull Image image, @NonNull Rect location) {
mImage = requireNonNull(image, "image");
mLocation = requireNonNull(location);
requireNonNull(mImage.getHardwareBuffer(), "image must be a hardware image");
}
synchronized RenderNode getDisplayList() {
if (mNode == null) {
mNode = new RenderNode("Tile{" + Integer.toHexString(mImage.hashCode()) + "}");
}
if (mNode.hasDisplayList()) {
return mNode;
}
final int w = Math.min(mImage.getWidth(), mLocation.width());
final int h = Math.min(mImage.getHeight(), mLocation.height());
mNode.setPosition(0, 0, w, h);
RecordingCanvas canvas = mNode.beginRecording(w, h);
canvas.save();
canvas.clipRect(0, 0, mLocation.width(), mLocation.height());
canvas.drawBitmap(Bitmap.wrapHardwareBuffer(mImage.getHardwareBuffer(), COLOR_SPACE),
0, 0, null);
canvas.restore();
mNode.endRecording();
return mNode;
}
Rect getLocation() {
return mLocation;
}
int getLeft() {
return mLocation.left;
}
int getTop() {
return mLocation.top;
}
int getRight() {
return mLocation.right;
}
int getBottom() {
return mLocation.bottom;
}
@Override
public synchronized void close() {
mImage.close();
if (mNode != null) {
mNode.discardDisplayList();
}
}
@Override
public String toString() {
return "{location=" + mLocation + ", source=" + mImage
+ ", buffer=" + mImage.getHardwareBuffer() + "}";
}
}