in rendering/src/com/android/tools/rendering/RenderLogger.java [378:515]
public void error(@Nullable String tag,
@Nullable String message,
@Nullable Throwable throwable,
@Nullable Object viewCookie,
@Nullable Object data) {
String description = describe(message, throwable);
if (throwable != null) {
if (throwable instanceof ClassNotFoundException) {
// The LayoutlibCallback is given a chance to resolve classes,
// and when it fails, it will record it in its own list which
// is displayed in a special way (with action hyperlinks etc).
// Therefore, include these messages in the visible render log,
// especially since the user message from a ClassNotFoundException
// is really not helpful (it just lists the class name without
// even mentioning that it is a class-not-found exception.)
return;
}
if (isIssue164378(throwable)) {
return;
}
if ("Unable to find the layout for Action Bar.".equals(description)) {
description += "\nConsider updating to a more recent version of appcompat, or switch the rendering library in the IDE " +
"down to API 21";
}
if (description.isEmpty()) {
description = "Exception raised during rendering";
}
else if (description.equals(throwable.getLocalizedMessage()) || description.equals(throwable.getMessage())) {
description = "Exception raised during rendering: " + description;
}
else if (message != null && message.startsWith("Failed to configure parser for ") && message.endsWith(DOT_PNG)) {
// See if it looks like a mismatched bitmap/color; if so, make a more intuitive error message
StackTraceElement[] frames = throwable.getStackTrace();
for (StackTraceElement frame : frames) {
if (frame.getMethodName().equals("createFromXml") && frame.getClassName().equals("android.content.res.ColorStateList")) {
String path = message.substring("Failed to configure parser for ".length());
RenderProblem.Html problem = RenderProblem.create(WARNING);
problem.tag("bitmapAsColor");
// deliberately not setting the throwable on the problem: exception is misleading
HtmlBuilder builder = problem.getHtmlBuilder();
builder.add("Resource error: Attempted to load a bitmap as a color state list.").newline();
builder.add("Verify that your style/theme attributes are correct, and make sure layouts are using the right attributes.");
builder.newline().newline();
path = FileUtil.toSystemIndependentName(path);
String basePath = myProjectBasePath == null ? null : FileUtil.toSystemIndependentName(myProjectBasePath);
if (basePath != null && path.startsWith(basePath)) {
path = path.substring(basePath.length());
path = StringUtil.trimStart(path, File.separator);
}
path = FileUtil.toSystemDependentName(path);
builder.add("The relevant image is ").add(path);
Set<String> widgets = Sets.newHashSet();
for (StackTraceElement f : frames) {
if (f.getMethodName().equals(CONSTRUCTOR_NAME)) {
String className = f.getClassName();
if (className.startsWith(WIDGET_PKG_PREFIX)) {
widgets.add(className.substring(className.lastIndexOf('.') + 1));
}
}
}
if (!widgets.isEmpty()) {
List<String> sorted = Lists.newArrayList(widgets);
Collections.sort(sorted);
builder.newline().newline().add("Widgets possibly involved: ").add(Joiner.on(", ").join(sorted));
}
addMessage(problem);
return;
}
else if (frame.getClassName().startsWith("com.android.tools.")) {
break;
}
}
}
else if (message != null && message.startsWith("Failed to parse file ")
&& throwable instanceof XmlPullParserException) {
XmlPullParserException e = (XmlPullParserException)throwable;
String msg = e.getMessage();
if (msg.startsWith("Binary XML file ")) {
int index = msg.indexOf(':');
if (index != -1 && index < msg.length() - 1) {
msg = msg.substring(index + 1).trim();
}
}
int lineNumber = e.getLineNumber();
int column = e.getColumnNumber();
// Strip out useless input sources pointing back to the internal reader
// e.g. "in java.io.InputStreamReader@4d957e26"
String reader = " in java.io.InputStreamReader@";
int index = msg.indexOf(reader);
if (index != -1) {
int end = msg.indexOf(')', index + 1);
if (end != -1) {
msg = msg.substring(0, index) + msg.substring(end);
}
}
String path = message.substring("Failed to parse file ".length());
RenderProblem.Html problem = RenderProblem.create(WARNING);
problem.tag("xmlParse");
// Don't include exceptions for XML parser errors: that's just displaying irrelevant
// information about how we ended up parsing the file
//problem.throwable(throwable);
HtmlBuilder builder = problem.getHtmlBuilder();
if (lineNumber != -1) {
builder.add("Line ").add(Integer.toString(lineNumber)).add(": ");
}
builder.add(msg);
if (lineNumber != -1) {
builder.add(" (");
File file = new File(path);
String url = HtmlLinkManager.createFilePositionUrl(file, lineNumber, column);
if (url != null) {
builder.addLink("Show", url);
builder.add(")");
}
}
addMessage(problem);
return;
}
else if (throwable instanceof StackOverflowError) {
// StackOverflowError exceptions can have very large stack traces, limit the size when needed
throwable = summarizeStackOverFlowException((StackOverflowError)throwable);
}
myHaveExceptions = true;
}
addTag(tag);
addMessage(myRenderProblemBuilder.build(throwable, tag, description));
}