use of com.android.utils.HtmlBuilder in project android by JetBrains.
the class RenderErrorContributor method reportRtlNotEnabled.
private void reportRtlNotEnabled(@NotNull RenderLogger logger, @Nullable RenderTask task) {
ApplicationManager.getApplication().runReadAction(() -> {
Project project = logger.getProject();
if (project == null || project.isDisposed()) {
return;
}
Module module = logger.getModule();
if (module == null) {
return;
}
AndroidFacet facet = AndroidFacet.getInstance(module);
Manifest manifest = facet != null ? facet.getManifest() : null;
Application application = manifest != null ? manifest.getApplication() : null;
if (application == null) {
return;
}
final XmlTag applicationTag = application.getXmlTag();
if (applicationTag == null) {
return;
}
HtmlBuilder builder = new HtmlBuilder();
builder.add("(").addLink("Add android:supportsRtl=\"true\" to the manifest", logger.getLinkManager().createRunnableLink(() -> {
new SetAttributeFix(project, applicationTag, AndroidManifest.ATTRIBUTE_SUPPORTS_RTL, ANDROID_URI, VALUE_TRUE).execute();
EditorDesignSurface surface = task != null ? task.getDesignSurface() : null;
if (surface != null) {
surface.requestRender(true);
}
})).add(")");
addIssue().setSeverity(HighlightSeverity.ERROR).setSummary("RTL support requires android:supportsRtl=\"true\" in the manifest").setHtmlContent(builder).build();
});
}
use of com.android.utils.HtmlBuilder in project android by JetBrains.
the class RenderErrorContributor method reportOtherProblems.
private void reportOtherProblems(@NotNull RenderLogger logger, RenderTask task) {
List<RenderProblem> messages = logger.getMessages();
if (messages == null || messages.isEmpty()) {
return;
}
Set<String> seenTags = Sets.newHashSet();
for (RenderProblem message : messages) {
String tag = message.getTag();
if (tag != null && seenTags.contains(tag)) {
continue;
}
seenTags.add(tag);
if (tag != null) {
if (LayoutLog.TAG_RESOURCES_FORMAT.equals(tag)) {
reportTagResourceFormat(myResult, message);
continue;
} else if (LayoutLog.TAG_RTL_NOT_ENABLED.equals(tag)) {
reportRtlNotEnabled(logger, task);
continue;
} else if (LayoutLog.TAG_RTL_NOT_SUPPORTED.equals(tag)) {
addIssue().setSeverity(HighlightSeverity.ERROR).setSummary("RTL support requires API level >= 17").setHtmlContent(new HtmlBuilder().addHtml(message.getHtml())).build();
continue;
}
}
HtmlBuilder builder = new HtmlBuilder();
String html = message.getHtml();
Throwable throwable = message.getThrowable();
String summary = "Render problem";
if (throwable != null) {
if (!reportSandboxError(throwable, false, true)) {
if (reportThrowable(builder, throwable, !html.isEmpty() || !message.isDefaultHtml())) {
// The error was hidden.
if (!html.isEmpty()) {
builder.getStringBuilder().append(html);
builder.newlineIfNecessary();
}
summary = throwable.getLocalizedMessage() != null ? throwable.getLocalizedMessage() : summary;
}
} else {
// This was processed as a Sandbox error
continue;
}
} else {
if (html.contains("has been edited more recently")) {
summary = "Build out-of-date";
}
builder.getStringBuilder().append(html);
builder.newlineIfNecessary();
}
addRefreshAction(builder);
addIssue().setSeverity(HighlightSeverity.ERROR).setSummary(summary).setHtmlContent(builder).build();
}
}
use of com.android.utils.HtmlBuilder in project android by JetBrains.
the class RenderLogger method error.
@Override
public void error(@Nullable String tag, @Nullable String message, @Nullable Throwable throwable, @Nullable Object data) {
String description = describe(message, throwable);
if (LOG_ALL) {
boolean token = RenderSecurityManager.enterSafeRegion(myCredential);
try {
LOG.warn(String.format("%1$s: %2$s", myName, description), throwable);
} finally {
RenderSecurityManager.exitSafeRegion(token);
}
}
if (throwable != null) {
if (throwable instanceof ClassNotFoundException) {
// even mentioning that it is a class-not-found exception.)
return;
}
if (checkForIssue164378(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.equals(throwable.getLocalizedMessage()) || description.equals(throwable.getMessage())) {
description = "Exception raised during rendering: " + description;
} else if (message == null) {
// See if it looks like the known issue with CalendarView; if so, add a more intuitive message
StackTraceElement[] stackTrace = throwable.getStackTrace();
if (stackTrace.length >= 2 && stackTrace[0].getClassName().equals("android.text.format.DateUtils") && stackTrace[1].getClassName().equals("android.widget.CalendarView")) {
RenderProblem.Html problem = RenderProblem.create(WARNING);
problem.tag("59732");
problem.throwable(throwable);
HtmlBuilder builder = problem.getHtmlBuilder();
builder.add("<CalendarView> and <DatePicker> are broken in this version of the rendering library. " + "Try updating your SDK in the SDK Manager when issue 59732 is fixed.");
builder.add(" (");
builder.addLink("Open Issue 59732", "http://b.android.com/59732");
builder.add(", ");
ShowExceptionFix detailsFix = new ShowExceptionFix(getModule().getProject(), throwable);
builder.addLink("Show Exception", getLinkManager().createRunnableLink(detailsFix));
builder.add(")");
addMessage(problem);
return;
} else if (stackTrace.length >= 2 && stackTrace[0].getClassName().equals("android.support.v7.widget.RecyclerView") && stackTrace[0].getMethodName().equals("onMeasure") && stackTrace[1].getClassName().equals("android.view.View") && throwable.toString().equals("java.lang.NullPointerException")) {
RenderProblem.Html problem = RenderProblem.create(WARNING);
String issue = "72117";
problem.tag(issue);
problem.throwable(throwable);
HtmlBuilder builder = problem.getHtmlBuilder();
builder.add("The new RecyclerView does not yet work in Studio. We are working on a fix. ");
// TODO: Add more specific error message here when we know where we are fixing it, e.g. either
// to update their layoutlib (if we work around it there), or a new version of the recyclerview AAR.
builder.add(" (");
builder.addLink("Open Issue " + issue, "http://b.android.com/" + issue);
builder.add(", ");
ShowExceptionFix detailsFix = new ShowExceptionFix(myModule.getProject(), throwable);
builder.addLink("Show Exception", getLinkManager().createRunnableLink(detailsFix));
builder.add(")");
addMessage(problem);
return;
}
} else if (message.equals("onMeasure error") && throwable.toString().startsWith("java.lang.NoSuchMethodError: android.support.constraint.solver.widgets.Guideline.setRelative")) {
RenderProblem.Html problem = RenderProblem.create(WARNING);
String issue = "214853";
problem.tag(issue);
problem.throwable(throwable);
HtmlBuilder builder = problem.getHtmlBuilder();
builder.add("You appear to be using constraint layout version alpha3 or earlier; you must use version alpha4 or later " + "with this version of the layout editor (because the API for guidelines changed incompatibly as of alpha4.)");
builder.add(" (");
builder.addLink("Update Library", getLinkManager().createRunnableLink(() -> UpgradeConstraintLayoutFix.apply(myModule)));
builder.add(", ");
ShowExceptionFix detailsFix = new ShowExceptionFix(myModule.getProject(), throwable);
builder.addLink("Show Exception", getLinkManager().createRunnableLink(detailsFix));
builder.add(")");
addMessage(problem);
return;
} else if (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 = FileUtil.toSystemIndependentName(myModule.getProject().getBasePath());
if (path.startsWith(basePath)) {
path = path.substring(basePath.length());
if (path.startsWith(File.separator)) {
path = path.substring(File.separator.length());
}
}
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.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;
}
recordThrowable(throwable);
myHaveExceptions = true;
}
addTag(tag);
if (getProject() == null) {
addMessage(RenderProblem.createPlain(ERROR, description).tag(tag).throwable(throwable));
} else {
addMessage(RenderProblem.createPlain(ERROR, description, getProject(), getLinkManager(), throwable).tag(tag));
}
}
use of com.android.utils.HtmlBuilder in project android by JetBrains.
the class RenderProblem method createPlain.
@NotNull
public static RenderProblem createPlain(@NotNull HighlightSeverity severity, @NotNull String message, @NotNull Project project, @NotNull HtmlLinkManager linkManager, @Nullable Throwable throwable) {
Html problem = new Html(severity, ourNextOrdinal++);
HtmlBuilder builder = problem.getHtmlBuilder();
builder.add(message);
if (throwable != null) {
String url = linkManager.createRunnableLink(new ShowExceptionFix(project, throwable));
builder.add(" (").addLink("Details", url).add(")");
problem.throwable(throwable);
if (message.equals(throwable.getMessage())) {
problem.myIsDefaultHtml = true;
}
}
return problem;
}
use of com.android.utils.HtmlBuilder in project android by JetBrains.
the class ViewLoader method checkModified.
/** Checks that the given class has not been edited since the last compilation (and if it has, logs a warning to the user) */
private void checkModified(@NotNull String fqcn) {
if (DumbService.getInstance(myModule.getProject()).isDumb()) {
// If the index is not ready, we can not check the modified time since it requires accessing the PSI
return;
}
if (myModuleClassLoader != null && myModuleClassLoader.isSourceModified(fqcn, myCredential) && !myRecentlyModifiedClasses.contains(fqcn)) {
assert myLogger != null;
myRecentlyModifiedClasses.add(fqcn);
RenderProblem.Html problem = RenderProblem.create(WARNING);
HtmlBuilder builder = problem.getHtmlBuilder();
String className = fqcn.substring(fqcn.lastIndexOf('.') + 1);
builder.addLink("The " + className + " custom view has been edited more recently than the last build: ", "Build", " the project.", myLogger.getLinkManager().createBuildProjectUrl());
myLogger.addMessage(problem);
}
}
Aggregations