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

Commit 2a9fa896 authored by Romain Guy's avatar Romain Guy
Browse files

Don't build display lists for views with a layer.

This could cause the draw() code of views to be invoked too often
or worse, called with the wrong canvas. For instance, a view backed
by a software layer could get its draw() method called to record a
display list. Using a software layer is the recommended way to use
drawing operations not supported in hardware. Since we would
sometimes call the draw() method with the hardware backend anyway,
the app could crash by executing an unsupported operation.

Change-Id: Ib5f9a3a4c6f3efff5e0162ecd73d2dffe06e30a6
parent 462785fa
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -2909,6 +2909,7 @@ public class View implements Drawable.Callback, Drawable.Callback2, KeyEvent.Cal
                        initializeScrollbars(a);
                    }
                    break;
                //noinspection deprecation
                case R.styleable.View_fadingEdge:
                    if (context.getApplicationInfo().targetSdkVersion >= ICE_CREAM_SANDWICH) {
                        // Ignore the attribute starting with ICS
+2 −2
Original line number Diff line number Diff line
@@ -34,7 +34,6 @@ import android.os.SystemClock;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
import android.view.View.AccessibilityDelegate;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.Animation;
@@ -2561,7 +2560,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager
        final View[] children = mChildren;
        for (int i = 0; i < count; i++) {
            final View child = children[i];
            if ((child.mViewFlags & VISIBILITY_MASK) == VISIBLE || child.getAnimation() != null) {
            if (((child.mViewFlags & VISIBILITY_MASK) == VISIBLE ||
                    child.getAnimation() != null) && child.getLayerType() == LAYER_TYPE_NONE) {
                child.mRecreateDisplayList = (child.mPrivateFlags & INVALIDATED) == INVALIDATED;
                child.mPrivateFlags &= ~INVALIDATED;
                child.getDisplayList();
+9 −0
Original line number Diff line number Diff line
@@ -30,6 +30,15 @@
        android:label="HwUi"
        android:hardwareAccelerated="true">

        <activity
                android:name="DisplayListLayersActivity"
                android:label="__DisplayListLayers">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        
        <activity
                android:name="TextFadeActivity"
                android:label="_TextFade">
+125 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2011 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


package com.android.test.hwui;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.widget.Button;
import android.widget.LinearLayout;

import static android.view.View.LAYER_TYPE_HARDWARE;
import static android.view.View.LAYER_TYPE_SOFTWARE;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;

@SuppressWarnings({"UnusedDeclaration"})
public class DisplayListLayersActivity extends Activity {
    private static final int VERTICAL_MARGIN = 12;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        LinearLayout root = createContainer();
        addChild(root, new LayerView(this, 0xffff0000, LAYER_TYPE_HARDWARE, "hardware"),
                WRAP_CONTENT, WRAP_CONTENT);
        addChild(root, new LayerView(this, 0xff0000ff, LAYER_TYPE_SOFTWARE, "software"),
                WRAP_CONTENT, WRAP_CONTENT);
        addChild(root, createButton(root), WRAP_CONTENT, WRAP_CONTENT);

        setContentView(root);
    }

    private Button createButton(final LinearLayout root) {
        Button button = new Button(this);
        button.setText("Invalidate");
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                for (int i = 0; i < root.getChildCount(); i++) {
                    View child = root.getChildAt(i);
                    if (child != v) {
                        child.invalidate();
                    }
                }
            }
        });

        return button;
    }

    private void addChild(LinearLayout root, View child, int width, int height) {
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(width, height);
        params.gravity = Gravity.CENTER_HORIZONTAL;
        params.setMargins(0, dipToPx(VERTICAL_MARGIN), 0, 0);
        root.addView(child, params);
    }

    private int dipToPx(int size) {
        return (int) (getResources().getDisplayMetrics().density * size + 0.5f);
    }

    private LinearLayout createContainer() {
        LinearLayout layout = new LinearLayout(this);
        layout.setOrientation(LinearLayout.VERTICAL);
        return layout;
    }

    private class LayerView extends View {
        private static final String LOG_TAG = "LayerView";
        private final Paint mPaint = new Paint();

        private final String mTag;

        LayerView(Context context, int color, int layerType, String tag) {
            super(context);

            mTag = tag;

            mPaint.setColor(color);
            setLayerType(layerType, null);
        }

        private void log(String tag) {
            Log.d(LOG_TAG, mTag + ": " + tag);
        }

        @Override
        public void invalidate() {
            log("invalidate");
            super.invalidate();
        }

        @Override
        protected void onDraw(Canvas canvas) {
            log("draw");
            canvas.drawRect(0, 0, getWidth(), getHeight(), mPaint);
        }

        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec) / 3,
                    MeasureSpec.getSize(heightMeasureSpec) / 3);
        }
    }
}