FileDocCategorySizeDatePackage
FakeShadowDrawable.javaAPI DocAndroid 5.1 API11001Thu Mar 12 22:22:42 GMT 2015com.android.systemui.recents.views

FakeShadowDrawable

public class FakeShadowDrawable extends android.graphics.drawable.Drawable
A rounded rectangle drawable which also includes a shadow around. This is mostly copied from frameworks/support/v7/cardview/eclair-mr1/android/support/v7/widget/ RoundRectDrawableWithShadow.java revision c42ba8c000d1e6ce85e152dfc17089a0a69e739f with a few modifications to suit our needs in SystemUI.

Fields Summary
static final double
COS_45
static final float
SHADOW_MULTIPLIER
final float
mInsetShadow
android.graphics.Paint
mCornerShadowPaint
android.graphics.Paint
mEdgeShadowPaint
final android.graphics.RectF
mCardBounds
float
mCornerRadius
android.graphics.Path
mCornerShadowPath
float
mMaxShadowSize
float
mRawMaxShadowSize
float
mShadowSize
float
mRawShadowSize
private boolean
mDirty
private final int
mShadowStartColor
private final int
mShadowEndColor
private boolean
mAddPaddingForCorners
private boolean
mPrintedShadowClipWarning
If shadow size is set to a value above max shadow, we print a warning
Constructors Summary
public FakeShadowDrawable(android.content.res.Resources resources, com.android.systemui.recents.RecentsConfiguration config)


         
        mShadowStartColor = resources.getColor(R.color.fake_shadow_start_color);
        mShadowEndColor = resources.getColor(R.color.fake_shadow_end_color);
        mInsetShadow = resources.getDimension(R.dimen.fake_shadow_inset);
        setShadowSize(resources.getDimensionPixelSize(R.dimen.fake_shadow_size),
                resources.getDimensionPixelSize(R.dimen.fake_shadow_size));
        mCornerShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
        mCornerShadowPaint.setStyle(Paint.Style.FILL);
        mCornerShadowPaint.setDither(true);
        mCornerRadius = config.taskViewRoundedCornerRadiusPx;
        mCardBounds = new RectF();
        mEdgeShadowPaint = new Paint(mCornerShadowPaint);
    
Methods Summary
private voidbuildComponents(android.graphics.Rect bounds)

        // Card is offset SHADOW_MULTIPLIER * maxShadowSize to account for the shadow shift.
        // We could have different top-bottom offsets to avoid extra gap above but in that case
        // center aligning Views inside the CardView would be problematic.
        final float verticalOffset = mMaxShadowSize * SHADOW_MULTIPLIER;
        mCardBounds.set(bounds.left + mMaxShadowSize, bounds.top + verticalOffset,
                bounds.right - mMaxShadowSize, bounds.bottom - verticalOffset);
        buildShadowCorners();
    
private voidbuildShadowCorners()

        RectF innerBounds = new RectF(-mCornerRadius, -mCornerRadius, mCornerRadius, mCornerRadius);
        RectF outerBounds = new RectF(innerBounds);
        outerBounds.inset(-mShadowSize, -mShadowSize);

        if (mCornerShadowPath == null) {
            mCornerShadowPath = new Path();
        } else {
            mCornerShadowPath.reset();
        }
        mCornerShadowPath.setFillType(Path.FillType.EVEN_ODD);
        mCornerShadowPath.moveTo(-mCornerRadius, 0);
        mCornerShadowPath.rLineTo(-mShadowSize, 0);
        // outer arc
        mCornerShadowPath.arcTo(outerBounds, 180f, 90f, false);
        // inner arc
        mCornerShadowPath.arcTo(innerBounds, 270f, -90f, false);
        mCornerShadowPath.close();

        float startRatio = mCornerRadius / (mCornerRadius + mShadowSize);
        mCornerShadowPaint.setShader(new RadialGradient(0, 0, mCornerRadius + mShadowSize,
                new int[]{mShadowStartColor, mShadowStartColor, mShadowEndColor},
                new float[]{0f, startRatio, 1f}
                , Shader.TileMode.CLAMP));

        // we offset the content shadowSize/2 pixels up to make it more realistic.
        // this is why edge shadow shader has some extra space
        // When drawing bottom edge shadow, we use that extra space.
        mEdgeShadowPaint.setShader(new LinearGradient(0, -mCornerRadius + mShadowSize, 0,
                -mCornerRadius - mShadowSize,
                new int[]{mShadowStartColor, mShadowStartColor, mShadowEndColor},
                new float[]{0f, .5f, 1f}, Shader.TileMode.CLAMP));
    
static floatcalculateHorizontalPadding(float maxShadowSize, float cornerRadius, boolean addPaddingForCorners)

        if (addPaddingForCorners) {
            return (float) (maxShadowSize + (1 - COS_45) * cornerRadius);
        } else {
            return maxShadowSize;
        }
    
static floatcalculateVerticalPadding(float maxShadowSize, float cornerRadius, boolean addPaddingForCorners)

        if (addPaddingForCorners) {
            return (float) (maxShadowSize * SHADOW_MULTIPLIER + (1 - COS_45) * cornerRadius);
        } else {
            return maxShadowSize * SHADOW_MULTIPLIER;
        }
    
public voiddraw(android.graphics.Canvas canvas)

        if (mDirty) {
            buildComponents(getBounds());
            mDirty = false;
        }
        canvas.translate(0, mRawShadowSize / 4);
        drawShadow(canvas);
        canvas.translate(0, -mRawShadowSize / 4);
    
private voiddrawShadow(android.graphics.Canvas canvas)

        final float edgeShadowTop = -mCornerRadius - mShadowSize;
        final float inset = mCornerRadius + mInsetShadow + mRawShadowSize / 2;
        final boolean drawHorizontalEdges = mCardBounds.width() - 2 * inset > 0;
        final boolean drawVerticalEdges = mCardBounds.height() - 2 * inset > 0;
        // LT
        int saved = canvas.save();
        canvas.translate(mCardBounds.left + inset, mCardBounds.top + inset);
        canvas.drawPath(mCornerShadowPath, mCornerShadowPaint);
        if (drawHorizontalEdges) {
            canvas.drawRect(0, edgeShadowTop,
                    mCardBounds.width() - 2 * inset, -mCornerRadius,
                    mEdgeShadowPaint);
        }
        canvas.restoreToCount(saved);
        // RB
        saved = canvas.save();
        canvas.translate(mCardBounds.right - inset, mCardBounds.bottom - inset);
        canvas.rotate(180f);
        canvas.drawPath(mCornerShadowPath, mCornerShadowPaint);
        if (drawHorizontalEdges) {
            canvas.drawRect(0, edgeShadowTop,
                    mCardBounds.width() - 2 * inset, -mCornerRadius + mShadowSize,
                    mEdgeShadowPaint);
        }
        canvas.restoreToCount(saved);
        // LB
        saved = canvas.save();
        canvas.translate(mCardBounds.left + inset, mCardBounds.bottom - inset);
        canvas.rotate(270f);
        canvas.drawPath(mCornerShadowPath, mCornerShadowPaint);
        if (drawVerticalEdges) {
            canvas.drawRect(0, edgeShadowTop,
                    mCardBounds.height() - 2 * inset, -mCornerRadius, mEdgeShadowPaint);
        }
        canvas.restoreToCount(saved);
        // RT
        saved = canvas.save();
        canvas.translate(mCardBounds.right - inset, mCardBounds.top + inset);
        canvas.rotate(90f);
        canvas.drawPath(mCornerShadowPath, mCornerShadowPaint);
        if (drawVerticalEdges) {
            canvas.drawRect(0, edgeShadowTop,
                    mCardBounds.height() - 2 * inset, -mCornerRadius, mEdgeShadowPaint);
        }
        canvas.restoreToCount(saved);
    
floatgetMinHeight()

        final float content = 2 * Math.max(mRawMaxShadowSize, mCornerRadius + mInsetShadow
                        + mRawMaxShadowSize * SHADOW_MULTIPLIER / 2);
        return content + (mRawMaxShadowSize * SHADOW_MULTIPLIER + mInsetShadow) * 2;
    
floatgetMinWidth()

        final float content = 2 *
                Math.max(mRawMaxShadowSize, mCornerRadius + mInsetShadow + mRawMaxShadowSize / 2);
        return content + (mRawMaxShadowSize + mInsetShadow) * 2;
    
public intgetOpacity()

        return PixelFormat.OPAQUE;
    
public booleangetPadding(android.graphics.Rect padding)

        int vOffset = (int) Math.ceil(calculateVerticalPadding(mRawMaxShadowSize, mCornerRadius,
                mAddPaddingForCorners));
        int hOffset = (int) Math.ceil(calculateHorizontalPadding(mRawMaxShadowSize, mCornerRadius,
                mAddPaddingForCorners));
        padding.set(hOffset, vOffset, hOffset, vOffset);
        return true;
    
protected voidonBoundsChange(android.graphics.Rect bounds)

        super.onBoundsChange(bounds);
        mDirty = true;
    
public voidsetAlpha(int alpha)

        mCornerShadowPaint.setAlpha(alpha);
        mEdgeShadowPaint.setAlpha(alpha);
    
public voidsetColorFilter(android.graphics.ColorFilter cf)

        mCornerShadowPaint.setColorFilter(cf);
        mEdgeShadowPaint.setColorFilter(cf);
    
voidsetShadowSize(float shadowSize, float maxShadowSize)

        if (shadowSize < 0 || maxShadowSize < 0) {
            throw new IllegalArgumentException("invalid shadow size");
        }
        if (shadowSize > maxShadowSize) {
            shadowSize = maxShadowSize;
            if (!mPrintedShadowClipWarning) {
                Log.w("CardView", "Shadow size is being clipped by the max shadow size. See "
                        + "{CardView#setMaxCardElevation}.");
                mPrintedShadowClipWarning = true;
            }
        }
        if (mRawShadowSize == shadowSize && mRawMaxShadowSize == maxShadowSize) {
            return;
        }
        mRawShadowSize = shadowSize;
        mRawMaxShadowSize = maxShadowSize;
        mShadowSize = shadowSize * SHADOW_MULTIPLIER + mInsetShadow;
        mMaxShadowSize = maxShadowSize + mInsetShadow;
        mDirty = true;
        invalidateSelf();