public void error()

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));
  }