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

Commit d30c141a authored by Deepanshu Gupta's avatar Deepanshu Gupta
Browse files

Improve error reporting on Exceptions in fw views.

When there's an exception during the inflation of a framework view (for
example invalid attributes), report the exception correctly. The earlier
behaviour assumed the exception to be a ClassNotFoundException and tried
to load it from the user's project. This is not longer the case.

Also, update the MockView class to a FrameLayout with a single TextView.
This means that the MockView is a ViewGroup and will not choke when
someone attempts to add a View to it (although, the view will be
silently dropped).

Change-Id: Ice003817ceb627ebfbbbb245ab6be10f9141e728
parent 7a062ed3
Loading
Loading
Loading
Loading
+27 −16
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import com.android.ide.common.rendering.api.ResourceReference;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.BridgeConstants;
import com.android.layoutlib.bridge.MockView;
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
import com.android.layoutlib.bridge.android.support.DrawerLayoutUtil;
@@ -126,6 +127,9 @@ public final class BridgeInflater extends LayoutInflater {
            if (view == null) {
                view = loadCustomView(name, attrs);
            }
        } catch (InflateException e) {
            // Don't catch the InflateException below as that results in hiding the real cause.
            throw e;
        } catch (Exception e) {
            // Wrap the real exception in a ClassNotFoundException, so that the calling method
            // can deal with it.
@@ -154,6 +158,12 @@ public final class BridgeInflater extends LayoutInflater {
                }
                ta.recycle();
            }
            if (!(e.getCause() instanceof ClassNotFoundException)) {
                // There is some unknown inflation exception in inflating a View that was found.
                view = new MockView(context, attrs);
                ((MockView) view).setText(name);
                Bridge.getLog().error(LayoutLog.TAG_BROKEN, e.getMessage(), e, null);
            } else {
                final Object lastContext = mConstructorArgs[0];
                mConstructorArgs[0] = context;
                // try to load the class from using the custom view loader
@@ -173,6 +183,7 @@ public final class BridgeInflater extends LayoutInflater {
                    mConstructorArgs[0] = lastContext;
                }
            }
        }

        setupViewInContext(view, attrs);

+64 −13
Original line number Diff line number Diff line
@@ -17,39 +17,90 @@
package com.android.layoutlib.bridge;

import android.content.Context;
import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.TextView;

/**
 * Base class for mocked views.
 *
 * TODO: implement onDraw and draw a rectangle in a random color with the name of the class
 * (or better the id of the view).
 * <p/>
 * FrameLayout with a single TextView. Doesn't allow adding any other views to itself.
 */
public class MockView extends TextView {
public class MockView extends FrameLayout {

    private final TextView mView;

    public MockView(Context context) {
        this(context, null);
    }

    public MockView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public MockView(Context context, AttributeSet attrs, int defStyle) {
        this(context, attrs, defStyle, 0);
    public MockView(Context context, AttributeSet attrs, int defStyleAttr) {
        this(context, attrs, defStyleAttr, 0);
    }

    public MockView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);

        setText(this.getClass().getSimpleName());
        setTextColor(0xFF000000);
        mView = new TextView(context, attrs);
        mView.setTextColor(0xFF000000);
        setGravity(Gravity.CENTER);
        setText(getClass().getSimpleName());
        addView(mView);
        setBackgroundColor(0xFF7F7F7F);
    }

    // Only allow adding one TextView.
    @Override
    public void addView(View child) {
        if (child == mView) {
            super.addView(child);
        }
    }

    @Override
    public void addView(View child, int index) {
        if (child == mView) {
            super.addView(child, index);
        }
    }

    @Override
    public void onDraw(Canvas canvas) {
        canvas.drawARGB(0xFF, 0x7F, 0x7F, 0x7F);
    public void addView(View child, int width, int height) {
        if (child == mView) {
            super.addView(child, width, height);
        }
    }

    @Override
    public void addView(View child, ViewGroup.LayoutParams params) {
        if (child == mView) {
            super.addView(child, params);
        }
    }

    @Override
    public void addView(View child, int index, ViewGroup.LayoutParams params) {
        if (child == mView) {
            super.addView(child, index, params);
        }
    }

    // The following methods are called by the IDE via reflection, and should be considered part
    // of the API.
    // Historically, MockView used to be a textView and had these methods. Now, we simply delegate
    // them to the contained textView.

    public void setText(CharSequence text) {
        mView.setText(text);
    }

        super.onDraw(canvas);
    public void setGravity(int gravity) {
        mView.setGravity(gravity);
    }
}