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.animation.LayoutTransition;
203cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurkaimport android.content.Context;
213cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurkaimport android.content.res.TypedArray;
223cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurkaimport android.graphics.Canvas;
233cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurkaimport android.graphics.LinearGradient;
243cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurkaimport android.graphics.Matrix;
253cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurkaimport android.graphics.Paint;
263cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurkaimport android.graphics.Shader;
273cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurkaimport android.graphics.drawable.Drawable;
283cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurkaimport android.util.AttributeSet;
293cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurkaimport android.view.View;
303cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurkaimport android.view.ViewConfiguration;
313cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurkaimport android.view.ViewGroup;
323cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurkaimport android.widget.LinearLayout;
333cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
343cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurkaimport com.android.systemui.R;
353cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
363cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurkapublic class RecentsScrollViewPerformanceHelper {
373cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    public static final boolean OPTIMIZE_SW_RENDERED_RECENTS = true;
383cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    public static final boolean USE_DARK_FADE_IN_HW_ACCELERATED_MODE = true;
393cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    private View mScrollView;
403cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    private RecentsCallback mCallback;
413cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
423cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    private int mFadingEdgeLength;
433cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    private Context mContext;
443cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    private boolean mIsVertical;
453cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    private boolean mSoftwareRendered = false;
463cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    private boolean mAttachedToWindow = false;
473cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
483cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    public static RecentsScrollViewPerformanceHelper create(Context context,
493cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            AttributeSet attrs, View scrollView, boolean isVertical) {
503cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        boolean isTablet = context.getResources().
513cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                getBoolean(R.bool.config_recents_interface_for_tablets);
523cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        if (!isTablet && (OPTIMIZE_SW_RENDERED_RECENTS || USE_DARK_FADE_IN_HW_ACCELERATED_MODE)) {
533cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            return new RecentsScrollViewPerformanceHelper(context, attrs, scrollView, isVertical);
543cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        } else {
553cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            return null;
563cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        }
573cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    }
583cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
593cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    public RecentsScrollViewPerformanceHelper(Context context,
603cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            AttributeSet attrs, View scrollView, boolean isVertical) {
613cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        mScrollView = scrollView;
623cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        mContext = context;
633cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.View);
643cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        mFadingEdgeLength = a.getDimensionPixelSize(android.R.styleable.View_fadingEdgeLength,
653cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                ViewConfiguration.get(context).getScaledFadingEdgeLength());
663cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        mIsVertical = isVertical;
673cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    }
683cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
693cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    public void onAttachedToWindowCallback(
703cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            RecentsCallback callback, LinearLayout layout, boolean hardwareAccelerated) {
713cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        mSoftwareRendered = !hardwareAccelerated;
723cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        if ((mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS)
733cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                || USE_DARK_FADE_IN_HW_ACCELERATED_MODE) {
743cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            mScrollView.setVerticalFadingEdgeEnabled(false);
753cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            mScrollView.setHorizontalFadingEdgeEnabled(false);
763cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        }
773cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    }
783cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
793cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    public void addViewCallback(View newLinearLayoutChild) {
803cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        if (mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS) {
81261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka            final RecentsPanelView.ViewHolder holder =
82261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka                    (RecentsPanelView.ViewHolder) newLinearLayoutChild.getTag();
83261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka            holder.labelView.setDrawingCacheEnabled(true);
84261277e1783ccebe5cb40763f8ef20d988dfe4caMichael Jurka            holder.labelView.buildDrawingCache();
853cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        }
863cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    }
873cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
883cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    public void drawCallback(Canvas canvas,
893cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            int left, int right, int top, int bottom, int scrollX, int scrollY,
903cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            float topFadingEdgeStrength, float bottomFadingEdgeStrength,
913cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            float leftFadingEdgeStrength, float rightFadingEdgeStrength) {
923cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
933cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        if ((mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS)
943cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                || USE_DARK_FADE_IN_HW_ACCELERATED_MODE) {
953cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            Paint p = new Paint();
963cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            Matrix matrix = new Matrix();
973cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            // use use a height of 1, and then wack the matrix each time we
983cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            // actually use it.
993cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            Shader fade = new LinearGradient(0, 0, 0, 1, 0xCC000000, 0, Shader.TileMode.CLAMP);
1003cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            // PULL OUT THIS CONSTANT
1013cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
1023cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            p.setShader(fade);
1033cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
1043cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            // draw the fade effect
1053cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            boolean drawTop = false;
1063cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            boolean drawBottom = false;
1073cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            boolean drawLeft = false;
1083cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            boolean drawRight = false;
1093cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
1103cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            float topFadeStrength = 0.0f;
1113cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            float bottomFadeStrength = 0.0f;
1123cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            float leftFadeStrength = 0.0f;
1133cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            float rightFadeStrength = 0.0f;
1143cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
1153cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            final float fadeHeight = mFadingEdgeLength;
1163cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            int length = (int) fadeHeight;
1173cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
1183cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            // clip the fade length if top and bottom fades overlap
1193cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            // overlapping fades produce odd-looking artifacts
1203cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            if (mIsVertical && (top + length > bottom - length)) {
1213cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                length = (bottom - top) / 2;
1223cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            }
1233cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
1243cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            // also clip horizontal fades if necessary
1253cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            if (!mIsVertical && (left + length > right - length)) {
1263cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                length = (right - left) / 2;
1273cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            }
1283cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
1293cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            if (mIsVertical) {
1303cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                topFadeStrength = Math.max(0.0f, Math.min(1.0f, topFadingEdgeStrength));
1313cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                drawTop = topFadeStrength * fadeHeight > 1.0f;
1323cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                bottomFadeStrength = Math.max(0.0f, Math.min(1.0f, bottomFadingEdgeStrength));
1333cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                drawBottom = bottomFadeStrength * fadeHeight > 1.0f;
1343cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            }
1353cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
1363cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            if (!mIsVertical) {
1373cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                leftFadeStrength = Math.max(0.0f, Math.min(1.0f, leftFadingEdgeStrength));
1383cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                drawLeft = leftFadeStrength * fadeHeight > 1.0f;
1393cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                rightFadeStrength = Math.max(0.0f, Math.min(1.0f, rightFadingEdgeStrength));
1403cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                drawRight = rightFadeStrength * fadeHeight > 1.0f;
1413cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            }
1423cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
1433cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            if (drawTop) {
1443cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                matrix.setScale(1, fadeHeight * topFadeStrength);
1453cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                matrix.postTranslate(left, top);
1463cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                fade.setLocalMatrix(matrix);
1473cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                canvas.drawRect(left, top, right, top + length, p);
1483cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            }
1493cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
1503cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            if (drawBottom) {
1513cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                matrix.setScale(1, fadeHeight * bottomFadeStrength);
1523cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                matrix.postRotate(180);
1533cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                matrix.postTranslate(left, bottom);
1543cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                fade.setLocalMatrix(matrix);
1553cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                canvas.drawRect(left, bottom - length, right, bottom, p);
1563cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            }
1573cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
1583cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            if (drawLeft) {
1593cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                matrix.setScale(1, fadeHeight * leftFadeStrength);
1603cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                matrix.postRotate(-90);
1613cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                matrix.postTranslate(left, top);
1623cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                fade.setLocalMatrix(matrix);
1633cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                canvas.drawRect(left, top, left + length, bottom, p);
1643cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            }
1653cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
1663cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            if (drawRight) {
1673cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                matrix.setScale(1, fadeHeight * rightFadeStrength);
1683cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                matrix.postRotate(90);
1693cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                matrix.postTranslate(right, top);
1703cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                fade.setLocalMatrix(matrix);
1713cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka                canvas.drawRect(right - length, top, right, bottom, p);
1723cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka            }
1733cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        }
1743cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    }
1753cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
1763cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    public int getVerticalFadingEdgeLengthCallback() {
1773cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        return mFadingEdgeLength;
1783cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    }
1793cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
1803cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    public int getHorizontalFadingEdgeLengthCallback() {
1813cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka        return mFadingEdgeLength;
1823cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka    }
1833cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka
1843cd0a593937c0724d77db1e2e3995255cfae61acMichael Jurka}
185