Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 197315e3 authored by Alan Viverette's avatar Alan Viverette
Browse files

Use layers for reveal drawable

Change-Id: I82887bb0a3994127ec0bd43ac017d51901a40488
parent 23ab74de
Loading
Loading
Loading
Loading
+41 −48
Original line number Diff line number Diff line
@@ -17,14 +17,11 @@
package android.graphics.drawable;

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.Shader.TileMode;
import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
@@ -70,15 +67,11 @@ public class RevealDrawable extends LayerDrawable {
    /** Target density, used to scale density-independent pixels. */
    private float mDensity = 1.0f;

    // Masking layer.
    private Bitmap mMaskBitmap;
    private Canvas mMaskCanvas;
    private Paint mMaskPaint;
    /** Paint used to control appearance of ripples. */
    private Paint mRipplePaint;

    // Reveal layer.
    private Bitmap mRevealBitmap;
    private Canvas mRevealCanvas;
    private Paint mRevealPaint;
    /** Paint used to control reveal layer masking. */
    private Paint mMaskingPaint;

    /**
     * Create a new reveal drawable with the specified list of layers. At least
@@ -232,61 +225,61 @@ public class RevealDrawable extends LayerDrawable {

    @Override
    public void draw(Canvas canvas) {
        final Drawable lower = getDrawable(0);
        lower.draw(canvas);
        final int layerCount = getNumberOfLayers();
        if (layerCount == 0) {
            return;
        }

        // No ripples? No problem.
        if (mActiveRipples == null || mActiveRipples.isEmpty()) {
        getDrawable(0).draw(canvas);

        final ArrayList<Ripple> activeRipples = mActiveRipples;
        if (layerCount == 1 || activeRipples == null || activeRipples.isEmpty()) {
            // Nothing to reveal, we're done here.
            return;
        }

        // Ensure we have a mask buffer.
        final Rect bounds = getBounds();
        final int width = bounds.width();
        final int height = bounds.height();
        if (mMaskBitmap == null) {
            mMaskBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8);
            mMaskCanvas = new Canvas(mMaskBitmap);
            mMaskPaint = new Paint();
            mMaskPaint.setAntiAlias(true);
        } else if (mMaskBitmap.getHeight() < height || mMaskBitmap.getWidth() < width) {
            mMaskBitmap.recycle();
            mMaskBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8);
        }

        // Ensure we have a reveal buffer.
        if (mRevealBitmap == null) {
            mRevealBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
            mRevealCanvas = new Canvas(mRevealBitmap);
            mRevealPaint = new Paint();
            mRevealPaint.setAntiAlias(true);
            mRevealPaint.setShader(new BitmapShader(mRevealBitmap, TileMode.CLAMP, TileMode.CLAMP));
        } else if (mRevealBitmap.getHeight() < height || mRevealBitmap.getWidth() < width) {
            mRevealBitmap.recycle();
            mRevealBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        }

        // Draw ripples into the mask buffer.
        mMaskCanvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
        int n = mActiveRipples.size();

        if (mRipplePaint == null) {
            mRipplePaint = new Paint();
            mRipplePaint.setAntiAlias(true);
        }

        // Draw ripple mask into a buffer that merges using SRC_OVER.
        int layerSaveCount = -1;
        int n = activeRipples.size();
        for (int i = 0; i < n; i++) {
            final Ripple ripple = mActiveRipples.get(i);
            final Ripple ripple = activeRipples.get(i);
            if (!ripple.active()) {
                mActiveRipples.remove(i);
                activeRipples.remove(i);
                i--;
                n--;
            } else {
                ripple.draw(mMaskCanvas, mMaskPaint);
                if (layerSaveCount < 0) {
                    layerSaveCount = canvas.saveLayer(0, 0, width, height, null, 0);
                }

                ripple.draw(canvas, mRipplePaint);
            }
        }

        // Draw upper layer into the reveal buffer.
        mRevealCanvas.drawColor(Color.TRANSPARENT, Mode.CLEAR);
        final Drawable upper = getDrawable(1);
        upper.draw(mRevealCanvas);
        // If a layer was saved, it contains the ripple mask. Draw the reveal
        // into another layer and composite using SRC_IN, then composite onto
        // the original canvas.
        if (layerSaveCount >= 0) {
            if (mMaskingPaint == null) {
                mMaskingPaint = new Paint();
                mMaskingPaint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN));
            }

        // Draw mask buffer onto the canvas using the reveal shader.
        canvas.drawBitmap(mMaskBitmap, 0, 0, mRevealPaint);
            // TODO: When Drawable.setXfermode() is supported by all drawables,
            // we won't need an extra layer.
            canvas.saveLayer(0, 0, width, height, mMaskingPaint, 0);
            getDrawable(1).draw(canvas);
            canvas.restoreToCount(layerSaveCount);
        }
    }

    private static class RevealState extends LayerState {