/* * Copyright (C) 2019 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.quickstep; import static android.graphics.Shader.TileMode.CLAMP; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapShader; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.drawable.Drawable; import androidx.annotation.NonNull; import com.android.launcher3.R; import com.android.systemui.shared.recents.model.ThumbnailData; /** * Bitmap backed drawable that supports rotating the thumbnail bitmap depending on if the * orientation the thumbnail was taken in matches the desired orientation. In addition, the * thumbnail always fills into the containing bounds. */ public final class ThumbnailDrawable extends Drawable { private final Paint mPaint = new Paint(); private final Matrix mMatrix = new Matrix(); private final ThumbnailData mThumbnailData; private final BitmapShader mShader; private final RectF mDestRect = new RectF(); private final int mCornerRadius; private int mRequestedOrientation; public ThumbnailDrawable(Resources res, @NonNull ThumbnailData thumbnailData, int requestedOrientation) { mThumbnailData = thumbnailData; mRequestedOrientation = requestedOrientation; mCornerRadius = (int) res.getDimension(R.dimen.task_thumbnail_corner_radius); mShader = new BitmapShader(mThumbnailData.thumbnail, CLAMP, CLAMP); mPaint.setShader(mShader); mPaint.setAntiAlias(true); updateMatrix(); } /** * Set the requested orientation. * * @param orientation the orientation we want the thumbnail to be in */ public void setRequestedOrientation(int orientation) { if (mRequestedOrientation != orientation) { mRequestedOrientation = orientation; updateMatrix(); } } @Override public void draw(Canvas canvas) { if (mThumbnailData.thumbnail == null) { return; } canvas.drawRoundRect(mDestRect, mCornerRadius, mCornerRadius, mPaint); } @Override protected void onBoundsChange(Rect bounds) { super.onBoundsChange(bounds); mDestRect.set(bounds); updateMatrix(); } @Override public void setAlpha(int alpha) { final int oldAlpha = mPaint.getAlpha(); if (alpha != oldAlpha) { mPaint.setAlpha(alpha); invalidateSelf(); } } @Override public int getAlpha() { return mPaint.getAlpha(); } @Override public void setColorFilter(ColorFilter colorFilter) { mPaint.setColorFilter(colorFilter); invalidateSelf(); } @Override public ColorFilter getColorFilter() { return mPaint.getColorFilter(); } @Override public int getOpacity() { return PixelFormat.TRANSLUCENT; } private void updateMatrix() { if (mThumbnailData.thumbnail == null) { return; } mMatrix.reset(); float scaleX; float scaleY; Rect bounds = getBounds(); Bitmap thumbnail = mThumbnailData.thumbnail; if (mRequestedOrientation != mThumbnailData.orientation) { // Rotate and translate so that top left is the same. mMatrix.postRotate(90, 0, 0); mMatrix.postTranslate(thumbnail.getHeight(), 0); scaleX = (float) bounds.width() / thumbnail.getHeight(); scaleY = (float) bounds.height() / thumbnail.getWidth(); } else { scaleX = (float) bounds.width() / thumbnail.getWidth(); scaleY = (float) bounds.height() / thumbnail.getHeight(); } // Scale to fill. mMatrix.postScale(scaleX, scaleY); mShader.setLocalMatrix(mMatrix); } }