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

Commit 0211a0a1 authored by Romain Guy's avatar Romain Guy
Browse files

Gracefully handle drawing caches allocation failure.

Bug #3431451

This bug was causing ListView to not render properly when showing an item
larger than the maximum drawing cache size. ListView relies on the drawing
cache to correctly mask all the background pixels. However, if the cache
is not properly created, the background will show through even though
ListView.isOpaque() == true. This change detects this case and falls
back to the default non opaque behavior.

Change-Id: I30a45e7a03fb7ebb2b12f0e85c075c2901954c44
parent 676b1739
Loading
Loading
Loading
Loading
+12 −1
Original line number Diff line number Diff line
@@ -2138,6 +2138,13 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility

    private int[] mDrawableState = null;

    /**
     * Set to true when drawing cache is enabled and cannot be created.
     * 
     * @hide
     */
    public boolean mCachingFailed;

    private Bitmap mDrawingCache;
    private Bitmap mUnscaledDrawingCache;
    private DisplayList mDisplayList;
@@ -8355,6 +8362,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
     * @see #setLayerType(int, android.graphics.Paint)
     */
    public void setDrawingCacheEnabled(boolean enabled) {
        mCachingFailed = false;
        setFlags(enabled ? DRAWING_CACHE_ENABLED : 0, DRAWING_CACHE_ENABLED);
    }

@@ -8624,6 +8632,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
    public void buildDrawingCache(boolean autoScale) {
        if ((mPrivateFlags & DRAWING_CACHE_VALID) == 0 || (autoScale ?
                mDrawingCache == null : mUnscaledDrawingCache == null)) {
            mCachingFailed = false;

            if (ViewDebug.TRACE_HIERARCHY) {
                ViewDebug.trace(this, ViewDebug.HierarchyTraceType.BUILD_CACHE);
@@ -8649,6 +8658,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
                    (width * height * (opaque && !use32BitCache ? 2 : 4) >
                            ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize())) {
                destroyDrawingCache();
                mCachingFailed = true;
                return;
            }

@@ -8701,6 +8711,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
                    } else {
                        mUnscaledDrawingCache = null;
                    }
                    mCachingFailed = true;
                    return;
                }

+2 −2
Original line number Diff line number Diff line
@@ -152,12 +152,12 @@ public class ViewConfiguration {
     * should be at least equal to the size of the screen in ARGB888 format.
     */
    @Deprecated
    private static final int MAXIMUM_DRAWING_CACHE_SIZE = 320 * 480 * 4; // HVGA screen, ARGB8888
    private static final int MAXIMUM_DRAWING_CACHE_SIZE = 480 * 800 * 4; // ARGB8888

    /**
     * The coefficient of friction applied to flings/scrolls.
     */
    private static float SCROLL_FRICTION = 0.015f;
    private static final float SCROLL_FRICTION = 0.015f;

    /**
     * Max distance to overscroll for edge effects
+3 −4
Original line number Diff line number Diff line
@@ -17,10 +17,6 @@
package android.view;

import android.animation.LayoutTransition;
import android.view.animation.AlphaAnimation;
import com.android.internal.R;
import com.android.internal.util.Predicate;

import android.content.Context;
import android.content.res.Configuration;
import android.content.res.TypedArray;
@@ -39,10 +35,13 @@ import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.view.animation.LayoutAnimationController;
import android.view.animation.Transformation;
import com.android.internal.R;
import com.android.internal.util.Predicate;

import java.util.ArrayList;
import java.util.HashSet;
+3 −2
Original line number Diff line number Diff line
@@ -334,6 +334,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
     * the drawing cache was enabled on the children
     */
    boolean mCachingStarted;
    boolean mCachingActive;

    /**
     * The position of the view that received the down motion event
@@ -4169,7 +4170,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
        if (mScrollingCacheEnabled && !mCachingStarted) {
            setChildrenDrawnWithCacheEnabled(true);
            setChildrenDrawingCacheEnabled(true);
            mCachingStarted = true;
            mCachingStarted = mCachingActive = true;
        }
    }

@@ -4178,7 +4179,7 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
            mClearScrollingCache = new Runnable() {
                public void run() {
                    if (mCachingStarted) {
                        mCachingStarted = false;
                        mCachingStarted = mCachingActive = false;
                        setChildrenDrawnWithCacheEnabled(false);
                        if ((mPersistentDrawingCache & PERSISTENT_SCROLLING_CACHE) == 0) {
                            setChildrenDrawingCacheEnabled(false);
+16 −6
Original line number Diff line number Diff line
@@ -3013,12 +3013,9 @@ public class ListView extends AbsListView {
        return mItemsCanFocus;
    }

    /**
     * @hide Pending API council approval.
     */
    @Override
    public boolean isOpaque() {
        return (mCachingStarted && mIsCacheColorOpaque && mDividerIsOpaque &&
        return (mCachingActive && mIsCacheColorOpaque && mDividerIsOpaque &&
                hasOpaqueScrollbars()) || super.isOpaque();
    }

@@ -3071,6 +3068,10 @@ public class ListView extends AbsListView {

    @Override
    protected void dispatchDraw(Canvas canvas) {
        if (mCachingStarted) {
            mCachingActive = true;
        }

        // Draw the dividers
        final int dividerHeight = mDividerHeight;
        final Drawable overscrollHeader = mOverScrollHeader;
@@ -3164,7 +3165,6 @@ public class ListView extends AbsListView {
                }
            } else {
                int top;
                int listTop = effectivePaddingTop;

                final int scrollY = mScrollY;

@@ -3181,7 +3181,7 @@ public class ListView extends AbsListView {
                        View child = getChildAt(i);
                        top = child.getTop();
                        // Don't draw dividers next to items that are not enabled
                        if (top > listTop) {
                        if (top > effectivePaddingTop) {
                            if ((areAllItemsSelectable ||
                                    (adapter.isEnabled(first + i) && (i == count - 1 ||
                                            adapter.isEnabled(first + i + 1))))) {
@@ -3220,6 +3220,15 @@ public class ListView extends AbsListView {
        super.dispatchDraw(canvas);
    }

    @Override
    protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
        boolean more = super.drawChild(canvas, child, drawingTime);
        if (mCachingActive && child.mCachingFailed) {
            mCachingActive = false;
        }
        return more;
    }

    /**
     * Draws a divider for the given child in the given bounds.
     *
@@ -3558,6 +3567,7 @@ public class ListView extends AbsListView {

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        //noinspection SimplifiableIfStatement
        if (mItemsCanFocus && ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) {
            // Don't handle edge touches immediately -- they may actually belong to one of our
            // descendants.