HolographicOutlineHelper.java revision 64a3cd4f204dd5f3676249d50aa0881b2e279b1f
15f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka/*
25f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * Copyright (C) 2008 The Android Open Source Project
35f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka *
45f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * Licensed under the Apache License, Version 2.0 (the "License");
55f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * you may not use this file except in compliance with the License.
65f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * You may obtain a copy of the License at
75f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka *
85f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka *      http://www.apache.org/licenses/LICENSE-2.0
95f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka *
105f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * Unless required by applicable law or agreed to in writing, software
115f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * distributed under the License is distributed on an "AS IS" BASIS,
125f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * See the License for the specific language governing permissions and
145f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka * limitations under the License.
155f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka */
165f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka
175f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurkapackage com.android.launcher2;
185f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka
195f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurkaimport android.graphics.Bitmap;
205f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurkaimport android.graphics.BlurMaskFilter;
215f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurkaimport android.graphics.Canvas;
225f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurkaimport android.graphics.Paint;
235f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurkaimport android.graphics.PorterDuff;
245f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurkaimport android.graphics.PorterDuffXfermode;
255f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka
265f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurkapublic class HolographicOutlineHelper {
275f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    private final Paint mHolographicPaint = new Paint();
2864a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung    private final Paint mExpensiveBlurPaint = new Paint();
295f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    private final Paint mErasePaint = new Paint();
305f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka
3164a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung    private static final BlurMaskFilter mThickOuterBlurMaskFilter = new BlurMaskFilter(6.0f,
3264a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung            BlurMaskFilter.Blur.OUTER);
3364a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung    private static final BlurMaskFilter mThinOuterBlurMaskFilter = new BlurMaskFilter(1.0f,
3464a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung            BlurMaskFilter.Blur.OUTER);
3564a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung    private static final BlurMaskFilter mThickInnerBlurMaskFilter = new BlurMaskFilter(4.0f,
3664a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung            BlurMaskFilter.Blur.NORMAL);
375f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka
3864a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung    public static float DEFAULT_STROKE_WIDTH = 6.0f;
3964a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung
4064a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung    HolographicOutlineHelper() {
415f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka        mHolographicPaint.setFilterBitmap(true);
425f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka        mHolographicPaint.setAntiAlias(true);
4364a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        mExpensiveBlurPaint.setFilterBitmap(true);
445f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka        mErasePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
455f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka        mErasePaint.setFilterBitmap(true);
465f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka        mErasePaint.setAntiAlias(true);
475f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    }
485f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka
495f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    /**
505f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka     * Returns the interpolated holographic highlight alpha for the effect we want when scrolling
515f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka     * pages.
525f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka     */
535f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    public float highlightAlphaInterpolator(float r) {
5464a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        float maxAlpha = 0.8f;
55e8878e3c5ac2b426be931018493ce82bd9c90378Winson Chung        return (float) Math.pow(maxAlpha * (1.0f - r), 1.5f);
565f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    }
575f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka
585f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    /**
595f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka     * Returns the interpolated view alpha for the effect we want when scrolling pages.
605f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka     */
615f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    public float viewAlphaInterpolator(float r) {
62e8878e3c5ac2b426be931018493ce82bd9c90378Winson Chung        final float pivot = 0.95f;
635f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka        if (r < pivot) {
64e8878e3c5ac2b426be931018493ce82bd9c90378Winson Chung            return (float) Math.pow(r / pivot, 1.5f);
655f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka        } else {
665f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka            return 1.0f;
675f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka        }
685f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    }
695f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka
705f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    /**
7164a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung     * Applies a more expensive and accurate outline to whatever is currently drawn in a specified
7264a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung     * bitmap.
735f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka     */
7464a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung    void applyExpensiveOutlineWithBlur(Bitmap srcDst, Canvas srcDstCanvas, int color,
7564a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung            int outlineColor) {
7664a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        // calculate the outer blur first
7764a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        mExpensiveBlurPaint.setMaskFilter(mThickOuterBlurMaskFilter);
7864a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        int[] outerBlurOffset = new int[2];
7964a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        Bitmap thickOuterBlur = srcDst.extractAlpha(mExpensiveBlurPaint, outerBlurOffset);
8064a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        mExpensiveBlurPaint.setMaskFilter(mThinOuterBlurMaskFilter);
8164a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        int[] thinOuterBlurOffset = new int[2];
8264a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        Bitmap thinOuterBlur = srcDst.extractAlpha(mExpensiveBlurPaint, thinOuterBlurOffset);
835f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka
8464a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        // calculate the inner blur
8564a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        srcDstCanvas.drawColor(0xFF000000, PorterDuff.Mode.SRC_OUT);
8664a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        mExpensiveBlurPaint.setMaskFilter(mThickInnerBlurMaskFilter);
8764a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        int[] thickInnerBlurOffset = new int[2];
8864a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        Bitmap thickInnerBlur = srcDst.extractAlpha(mExpensiveBlurPaint, thickInnerBlurOffset);
895f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka
9064a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        // mask out the inner blur
9164a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        srcDstCanvas.setBitmap(thickInnerBlur);
9264a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        srcDstCanvas.drawBitmap(srcDst, -thickInnerBlurOffset[0],
9364a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung                -thickInnerBlurOffset[1], mErasePaint);
9464a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        srcDstCanvas.drawRect(0, 0, -thickInnerBlurOffset[0], thickInnerBlur.getHeight(),
9564a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung                mErasePaint);
9664a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        srcDstCanvas.drawRect(0, 0, thickInnerBlur.getWidth(), -thickInnerBlurOffset[1],
9764a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung                mErasePaint);
985f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka
9964a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        // draw the inner and outer blur
10064a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        srcDstCanvas.setBitmap(srcDst);
10164a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        srcDstCanvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR);
10264a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        mHolographicPaint.setColor(color);
10364a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        srcDstCanvas.drawBitmap(thickInnerBlur, thickInnerBlurOffset[0], thickInnerBlurOffset[1],
10464a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung                mHolographicPaint);
10564a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        srcDstCanvas.drawBitmap(thickOuterBlur, outerBlurOffset[0], outerBlurOffset[1],
10664a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung                mHolographicPaint);
10764a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung
10864a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        // draw the bright outline
10964a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        mHolographicPaint.setColor(outlineColor);
11064a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        srcDstCanvas.drawBitmap(thinOuterBlur, thinOuterBlurOffset[0], thinOuterBlurOffset[1],
11164a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung                mHolographicPaint);
11264a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung
11364a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        // cleanup
11464a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        thinOuterBlur.recycle();
11564a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        thickOuterBlur.recycle();
11664a3cd4f204dd5f3676249d50aa0881b2e279b1fWinson Chung        thickInnerBlur.recycle();
1175f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka    }
1185f1c509d5ad1954a7e38e77db4d5f27c7345fd39Michael Jurka}