13cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka/*
23cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka * Copyright (C) 2011 The Android Open Source Project
33cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka *
43cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka * Licensed under the Apache License, Version 2.0 (the "License");
53cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka * you may not use this file except in compliance with the License.
63cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka * You may obtain a copy of the License at
73cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka *
83cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka *      http://www.apache.org/licenses/LICENSE-2.0
93cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka *
103cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka * Unless required by applicable law or agreed to in writing, software
113cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka * distributed under the License is distributed on an "AS IS" BASIS,
123cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka * See the License for the specific language governing permissions and
143cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka * limitations under the License.
153cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka */
163cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
173cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurkapackage com.android.systemui.recent;
183cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
193cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurkaimport android.content.Context;
203cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurkaimport android.content.res.TypedArray;
213cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurkaimport android.graphics.Canvas;
223cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurkaimport android.graphics.LinearGradient;
233cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurkaimport android.graphics.Matrix;
243cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurkaimport android.graphics.Paint;
253cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurkaimport android.graphics.Shader;
263cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurkaimport android.util.AttributeSet;
273cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurkaimport android.view.View;
283cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurkaimport android.view.ViewConfiguration;
293cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurkaimport android.widget.LinearLayout;
303cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
313cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurkaimport com.android.systemui.R;
323cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
333cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurkapublic class RecentsScrollViewPerformanceHelper {
343cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    public static final boolean OPTIMIZE_SW_RENDERED_RECENTS = true;
353cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    public static final boolean USE_DARK_FADE_IN_HW_ACCELERATED_MODE = true;
363cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    private View mScrollView;
373cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
383cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    private int mFadingEdgeLength;
393cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    private boolean mIsVertical;
403cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    private boolean mSoftwareRendered = false;
4131a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka    private Paint mBlackPaint;
4231a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka    private Paint mFadePaint;
4331a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka    private Matrix mFadeMatrix;
4431a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka    private LinearGradient mFade;
453cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
463cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    public static RecentsScrollViewPerformanceHelper create(Context context,
473cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            AttributeSet attrs, View scrollView, boolean isVertical) {
483cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        boolean isTablet = context.getResources().
493cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                getBoolean(R.bool.config_recents_interface_for_tablets);
503cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        if (!isTablet && (OPTIMIZE_SW_RENDERED_RECENTS || USE_DARK_FADE_IN_HW_ACCELERATED_MODE)) {
513cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            return new RecentsScrollViewPerformanceHelper(context, attrs, scrollView, isVertical);
523cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        } else {
533cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            return null;
543cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        }
553cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    }
563cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
573cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    public RecentsScrollViewPerformanceHelper(Context context,
583cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            AttributeSet attrs, View scrollView, boolean isVertical) {
593cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        mScrollView = scrollView;
603cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.View);
613cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        mFadingEdgeLength = a.getDimensionPixelSize(android.R.styleable.View_fadingEdgeLength,
623cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                ViewConfiguration.get(context).getScaledFadingEdgeLength());
633cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        mIsVertical = isVertical;
643cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    }
653cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
663cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    public void onAttachedToWindowCallback(
673cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            RecentsCallback callback, LinearLayout layout, boolean hardwareAccelerated) {
683cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        mSoftwareRendered = !hardwareAccelerated;
693cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        if ((mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS)
703cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                || USE_DARK_FADE_IN_HW_ACCELERATED_MODE) {
713cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            mScrollView.setVerticalFadingEdgeEnabled(false);
723cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            mScrollView.setHorizontalFadingEdgeEnabled(false);
733cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        }
743cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    }
753cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
763cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    public void addViewCallback(View newLinearLayoutChild) {
773cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        if (mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS) {
78261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka            final RecentsPanelView.ViewHolder holder =
79261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka                    (RecentsPanelView.ViewHolder) newLinearLayoutChild.getTag();
80261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka            holder.labelView.setDrawingCacheEnabled(true);
81261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka            holder.labelView.buildDrawingCache();
823cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        }
833cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    }
843cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
853cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    public void drawCallback(Canvas canvas,
863cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            int left, int right, int top, int bottom, int scrollX, int scrollY,
873cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            float topFadingEdgeStrength, float bottomFadingEdgeStrength,
8831a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka            float leftFadingEdgeStrength, float rightFadingEdgeStrength, int mPaddingTop) {
893cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
903cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        if ((mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS)
913cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                || USE_DARK_FADE_IN_HW_ACCELERATED_MODE) {
9231a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka            if (mFadePaint == null) {
9331a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka                mFadePaint = new Paint();
9431a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka                mFadeMatrix = new Matrix();
9531a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka                // use use a height of 1, and then wack the matrix each time we
9631a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka                // actually use it.
9731a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka                mFade = new LinearGradient(0, 0, 0, 1, 0xCC000000, 0, Shader.TileMode.CLAMP);
9831a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka                // PULL OUT THIS CONSTANT
9931a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka                mFadePaint.setShader(mFade);
10031a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka            }
1013cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
1023cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            // draw the fade effect
1033cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            boolean drawTop = false;
1043cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            boolean drawBottom = false;
1053cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            boolean drawLeft = false;
1063cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            boolean drawRight = false;
1073cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
1083cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            float topFadeStrength = 0.0f;
1093cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            float bottomFadeStrength = 0.0f;
1103cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            float leftFadeStrength = 0.0f;
1113cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            float rightFadeStrength = 0.0f;
1123cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
1133cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            final float fadeHeight = mFadingEdgeLength;
1143cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            int length = (int) fadeHeight;
1153cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
1163cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            // clip the fade length if top and bottom fades overlap
1173cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            // overlapping fades produce odd-looking artifacts
1183cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            if (mIsVertical && (top + length > bottom - length)) {
1193cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                length = (bottom - top) / 2;
1203cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            }
1213cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
1223cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            // also clip horizontal fades if necessary
1233cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            if (!mIsVertical && (left + length > right - length)) {
1243cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                length = (right - left) / 2;
1253cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            }
1263cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
1273cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            if (mIsVertical) {
1283cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                topFadeStrength = Math.max(0.0f, Math.min(1.0f, topFadingEdgeStrength));
1293cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                drawTop = topFadeStrength * fadeHeight > 1.0f;
1303cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, bottomFadingEdgeStrength));
1313cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                drawBottom = bottomFadeStrength * fadeHeight > 1.0f;
1323cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            }
1333cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
1343cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            if (!mIsVertical) {
1353cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                leftFadeStrength = Math.max(0.0f, Math.min(1.0f, leftFadingEdgeStrength));
1363cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                drawLeft = leftFadeStrength * fadeHeight > 1.0f;
1373cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                rightFadeStrength = Math.max(0.0f, Math.min(1.0f, rightFadingEdgeStrength));
1383cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                drawRight = rightFadeStrength * fadeHeight > 1.0f;
1393cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            }
1403cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
1413cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            if (drawTop) {
14231a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka                mFadeMatrix.setScale(1, fadeHeight * topFadeStrength);
14331a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka                mFadeMatrix.postTranslate(left, top);
14431a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka                mFade.setLocalMatrix(mFadeMatrix);
14531a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka                canvas.drawRect(left, top, right, top + length, mFadePaint);
14631a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka
14731a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka                if (mBlackPaint == null) {
14831a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka                    // Draw under the status bar at the top
14931a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka                    mBlackPaint = new Paint();
15031a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka                    mBlackPaint.setColor(0xFF000000);
15131a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka                }
15231a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka                canvas.drawRect(left, top - mPaddingTop, right, top, mBlackPaint);
1533cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            }
1543cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
1553cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            if (drawBottom) {
15631a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka                mFadeMatrix.setScale(1, fadeHeight * bottomFadeStrength);
15731a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka                mFadeMatrix.postRotate(180);
15831a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka                mFadeMatrix.postTranslate(left, bottom);
15931a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka                mFade.setLocalMatrix(mFadeMatrix);
16031a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka                canvas.drawRect(left, bottom - length, right, bottom, mFadePaint);
1613cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            }
1623cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
1633cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            if (drawLeft) {
16431a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka                mFadeMatrix.setScale(1, fadeHeight * leftFadeStrength);
16531a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka                mFadeMatrix.postRotate(-90);
16631a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka                mFadeMatrix.postTranslate(left, top);
16731a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka                mFade.setLocalMatrix(mFadeMatrix);
16831a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka                canvas.drawRect(left, top, left + length, bottom, mFadePaint);
1693cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            }
1703cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
1713cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            if (drawRight) {
17231a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka                mFadeMatrix.setScale(1, fadeHeight * rightFadeStrength);
17331a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka                mFadeMatrix.postRotate(90);
17431a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka                mFadeMatrix.postTranslate(right, top);
17531a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka                mFade.setLocalMatrix(mFadeMatrix);
17631a6fb3b086ce4927f5aafc705a640c9abc8870dMichael Jurka                canvas.drawRect(right - length, top, right, bottom, mFadePaint);
1773cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            }
1783cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        }
1793cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    }
1803cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
1813cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    public int getVerticalFadingEdgeLengthCallback() {
1823cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        return mFadingEdgeLength;
1833cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    }
1843cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
1853cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    public int getHorizontalFadingEdgeLengthCallback() {
1863cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        return mFadingEdgeLength;
1873cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    }
1883cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
1893cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka}
190