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
This commit is contained in:
@@ -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,23 +158,30 @@ public final class BridgeInflater extends LayoutInflater {
|
||||
}
|
||||
ta.recycle();
|
||||
}
|
||||
final Object lastContext = mConstructorArgs[0];
|
||||
mConstructorArgs[0] = context;
|
||||
// try to load the class from using the custom view loader
|
||||
try {
|
||||
view = loadCustomView(name, attrs);
|
||||
} catch (Exception e2) {
|
||||
// Wrap the real exception in an InflateException so that the calling
|
||||
// method can deal with it.
|
||||
InflateException exception = new InflateException();
|
||||
if (!e2.getClass().equals(ClassNotFoundException.class)) {
|
||||
exception.initCause(e2);
|
||||
} else {
|
||||
exception.initCause(e);
|
||||
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
|
||||
try {
|
||||
view = loadCustomView(name, attrs);
|
||||
} catch (Exception e2) {
|
||||
// Wrap the real exception in an InflateException so that the calling
|
||||
// method can deal with it.
|
||||
InflateException exception = new InflateException();
|
||||
if (!e2.getClass().equals(ClassNotFoundException.class)) {
|
||||
exception.initCause(e2);
|
||||
} else {
|
||||
exception.initCause(e);
|
||||
}
|
||||
throw exception;
|
||||
} finally {
|
||||
mConstructorArgs[0] = lastContext;
|
||||
}
|
||||
throw exception;
|
||||
} finally {
|
||||
mConstructorArgs[0] = lastContext;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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 onDraw(Canvas canvas) {
|
||||
canvas.drawARGB(0xFF, 0x7F, 0x7F, 0x7F);
|
||||
public void addView(View child, int index) {
|
||||
if (child == mView) {
|
||||
super.addView(child, index);
|
||||
}
|
||||
}
|
||||
|
||||
super.onDraw(canvas);
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
|
||||
public void setGravity(int gravity) {
|
||||
mView.setGravity(gravity);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user