| /* |
| * 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 android.annotation.Nullable; |
| import android.graphics.Canvas; |
| import android.graphics.ColorFilter; |
| import android.graphics.PixelFormat; |
| import android.graphics.Rect; |
| import android.graphics.RenderNode; |
| import android.graphics.drawable.Drawable; |
| import android.util.Log; |
| |
| /** |
| * Draws a set of hardware image tiles from a display list. The tiles exist in virtual coordinate |
| * space that may extend into positive or negative values. The origin is the upper-left-most corner |
| * of bounding box, which is drawn at 0,0 to the drawable (output) bounds. |
| */ |
| public class TiledImageDrawable extends Drawable { |
| |
| private static final String TAG = "TiledImageDrawable"; |
| |
| private final ImageTileSet mTiles; |
| private RenderNode mNode; |
| |
| public TiledImageDrawable(ImageTileSet tiles) { |
| mTiles = tiles; |
| mTiles.addOnContentChangedListener(this::onContentChanged); |
| } |
| |
| |
| private void onContentChanged() { |
| if (mNode != null && mNode.hasDisplayList()) { |
| mNode.discardDisplayList(); |
| } |
| invalidateSelf(); |
| } |
| |
| private void rebuildDisplayListIfNeeded() { |
| if (mNode != null && mNode.hasDisplayList()) { |
| return; |
| } |
| if (mNode == null) { |
| mNode = new RenderNode("TiledImageDrawable"); |
| } |
| mNode.setPosition(0, 0, mTiles.getWidth(), mTiles.getHeight()); |
| Canvas canvas = mNode.beginRecording(); |
| // Align content (virtual) top/left with 0,0, within the render node |
| canvas.translate(-mTiles.getLeft(), -mTiles.getTop()); |
| for (int i = 0; i < mTiles.size(); i++) { |
| ImageTile tile = mTiles.get(i); |
| canvas.save(); |
| canvas.translate(tile.getLeft(), tile.getTop()); |
| canvas.drawRenderNode(tile.getDisplayList()); |
| canvas.restore(); |
| } |
| mNode.endRecording(); |
| } |
| |
| /** |
| * Draws the tiled image to the canvas, with the top/left (virtual) coordinate aligned to 0,0 |
| * placed at left/top of the drawable's bounds. |
| */ |
| @Override |
| public void draw(Canvas canvas) { |
| rebuildDisplayListIfNeeded(); |
| if (canvas.isHardwareAccelerated()) { |
| Rect bounds = getBounds(); |
| canvas.save(); |
| canvas.clipRect(0, 0, bounds.width(), bounds.height()); |
| canvas.translate(-bounds.left, -bounds.top); |
| canvas.drawRenderNode(mNode); |
| canvas.restore(); |
| } else { |
| Log.d(TAG, "Canvas is not hardware accelerated. Skipping draw!"); |
| } |
| } |
| |
| @Override |
| public int getIntrinsicWidth() { |
| return mTiles.getWidth(); |
| } |
| |
| @Override |
| public int getIntrinsicHeight() { |
| return mTiles.getHeight(); |
| } |
| |
| @Override |
| public void setAlpha(int alpha) { |
| if (mNode.setAlpha(alpha / 255f)) { |
| invalidateSelf(); |
| } |
| } |
| |
| @Override |
| public void setColorFilter(@Nullable ColorFilter colorFilter) { |
| throw new IllegalArgumentException("not implemented"); |
| } |
| |
| @Override |
| public int getOpacity() { |
| return PixelFormat.OPAQUE; |
| } |
| } |