Merge 5226e79d9aca7f74b63cf2388638c2cf83435902 on remote branch

Change-Id: Iabfaf42efb9a9cfebd33ae4aa1d1d5094379cf73
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 0493bd2..22a2093 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -13,7 +13,7 @@
     <option name="myDefaultNotNull" value="android.annotation.NonNull" />
     <option name="myNullables">
       <value>
-        <list size="12">
+        <list size="13">
           <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
           <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
           <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
@@ -26,12 +26,13 @@
           <item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.Nullable" />
           <item index="10" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableDecl" />
           <item index="11" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableType" />
+          <item index="12" class="java.lang.String" itemvalue="org.eclipse.jdt.annotation.Nullable" />
         </list>
       </value>
     </option>
     <option name="myNotNulls">
       <value>
-        <list size="11">
+        <list size="12">
           <item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
           <item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
           <item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
@@ -43,11 +44,12 @@
           <item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.NonNull" />
           <item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullDecl" />
           <item index="10" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullType" />
+          <item index="11" class="java.lang.String" itemvalue="org.eclipse.jdt.annotation.NonNull" />
         </list>
       </value>
     </option>
   </component>
-  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_9" default="false" project-jdk-name="9" project-jdk-type="JavaSDK">
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_1_9" default="false" project-jdk-name="11" project-jdk-type="JavaSDK">
     <output url="file://$PROJECT_DIR$/out" />
   </component>
 </project>
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
index 1d59503..50836c1 100644
--- a/.idea/modules.xml
+++ b/.idea/modules.xml
@@ -10,6 +10,7 @@
       <module fileurl="file://$PROJECT_DIR$/remote/server/remote server.iml" filepath="$PROJECT_DIR$/remote/server/remote server.iml" group="remote" />
       <module fileurl="file://$PROJECT_DIR$/remote/tests/remote tests.iml" filepath="$PROJECT_DIR$/remote/tests/remote tests.iml" group="remote" />
       <module fileurl="file://$PROJECT_DIR$/studio-custom-widgets/studio-android-widgets.iml" filepath="$PROJECT_DIR$/studio-custom-widgets/studio-android-widgets.iml" />
+      <module fileurl="file://$PROJECT_DIR$/validator/validator.iml" filepath="$PROJECT_DIR$/validator/validator.iml" />
     </modules>
   </component>
 </project>
\ No newline at end of file
diff --git a/bridge/src/android/animation/PropertyValuesHolder_Delegate.java b/bridge/src/android/animation/PropertyValuesHolder_Delegate.java
index 07a0224..556a063 100644
--- a/bridge/src/android/animation/PropertyValuesHolder_Delegate.java
+++ b/bridge/src/android/animation/PropertyValuesHolder_Delegate.java
@@ -110,7 +110,8 @@
             method.setAccessible(true);
             method.invoke(target, args);
         } catch (IllegalAccessException | InvocationTargetException e) {
-            Bridge.getLog().error(null, "Unable to update property during animation", e, null);
+            Bridge.getLog().error(null, "Unable to update property during animation", e, null,
+                    null);
         }
     }
 
diff --git a/bridge/src/android/content/res/BridgeTypedArray.java b/bridge/src/android/content/res/BridgeTypedArray.java
index ec841de..458e613 100644
--- a/bridge/src/android/content/res/BridgeTypedArray.java
+++ b/bridge/src/android/content/res/BridgeTypedArray.java
@@ -265,7 +265,7 @@
             Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
                     String.format("\"%1$s\" in attribute \"%2$s\" is not a valid integer",
                             s, mNames[index]),
-                    null);
+                    null, null);
         }
         return defValue;
     }
@@ -288,7 +288,7 @@
             Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
                     String.format("\"%1$s\" in attribute \"%2$s\" cannot be converted to float.",
                             s, mNames[index]),
-                    null);
+                    null, null);
         }
         return defValue;
     }
@@ -446,7 +446,8 @@
                 // looks like we were unable to resolve the dimension value
                 Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
                         String.format("\"%1$s\" in attribute \"%2$s\" is not a valid format.",
-                                s, mNames[index]), null);
+                                s, mNames[index]),
+                        null, null);
             }
 
             return defValue;
@@ -477,7 +478,8 @@
             }
 
             Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
-                    "You must supply a " + name + " attribute.", null);
+                    "You must supply a " + name + " attribute.",
+                    null, null);
 
             return 0;
         }
@@ -548,7 +550,8 @@
         Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
                 String.format(
                         "\"%1$s\" in attribute \"%2$s\" cannot be converted to a fraction.",
-                        value, mNames[index]), null);
+                        value, mNames[index]),
+                null, null);
 
         return defValue;
     }
diff --git a/bridge/src/android/content/res/Resources_Delegate.java b/bridge/src/android/content/res/Resources_Delegate.java
index 1104397..cd57d5c 100644
--- a/bridge/src/android/content/res/Resources_Delegate.java
+++ b/bridge/src/android/content/res/Resources_Delegate.java
@@ -227,7 +227,7 @@
                 } else {
                     message = e.getMessage();
                 }
-                Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT, message, e, null);
+                Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT, message, e, null, null);
                 return 0;
             }
         }
@@ -375,16 +375,16 @@
                     } catch (NumberFormatException e) {
                         Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT,
                                 "Integer resource array contains non-integer value: \"" + element +
-                                        "\"", null);
+                                        "\"", null, null);
                     } catch (IllegalArgumentException e) {
                         Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT,
                                 "Integer resource array contains wrong color format: \"" + element +
-                                        "\"", null);
+                                        "\"", null, null);
                     }
                 } else {
                     Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT,
                             "Integer resource array contains non-integer value: \"" +
-                                    resValue.getElement(i) + "\"", null);
+                                    resValue.getElement(i) + "\"", null, null);
                 }
             }
             return values;
@@ -398,13 +398,13 @@
             } catch (NumberFormatException e) {
                 Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT,
                         "Integer resource array contains non-integer value: \"" + firstValue + "\"",
-                        null);
+                        null, null);
                 return new int[1];
             }
         } else {
             Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT,
                     "Integer resource array contains non-integer value: \"" +
-                            rv.getValue() + "\"", null);
+                            rv.getValue() + "\"", null, null);
             return new int[1];
         }
     }
@@ -437,13 +437,13 @@
                             String.format(
                                     "Resource with id 0x%1$X is not an array resource, but %2$s",
                                     id, type == null ? "null" : type.getDisplayName()),
-                            null);
+                            null, null);
                     return null;
                 }
                 if (!(resValue instanceof ArrayResourceValue)) {
                     Bridge.getLog().warning(LayoutLog.TAG_UNSUPPORTED,
                             "Obtaining resource arrays via getTextArray, getStringArray or getIntArray is not fully supported in this version of the IDE.",
-                            null);
+                            null, null);
                 }
                 return resValue;
             }
@@ -490,7 +490,7 @@
                 }
             } catch (XmlPullParserException e) {
                 Bridge.getLog().error(LayoutLog.TAG_BROKEN,
-                        "Failed to parse " + value.getValue(), e, null /*data*/);
+                        "Failed to parse " + value.getValue(), e, null, null /*data*/);
                 // we'll return null below.
             }
         }
@@ -513,7 +513,7 @@
                 return ResourceHelper.getXmlBlockParser(getContext(resources), value);
             } catch (XmlPullParserException e) {
                 Bridge.getLog().error(LayoutLog.TAG_BROKEN,
-                        "Failed to parse " + value.getValue(), e, null /*data*/);
+                        "Failed to parse " + value.getValue(), e, null, null /*data*/);
                 // we'll return null below.
             }
         }
@@ -948,7 +948,7 @@
                 return ResourceHelper.getXmlBlockParser(getContext(resources), value);
             } catch (XmlPullParserException e) {
                 Bridge.getLog().error(LayoutLog.TAG_BROKEN,
-                        "Failed to parse " + value.getValue(), e, null /*data*/);
+                        "Failed to parse " + value.getValue(), e, null, null /*data*/);
                 // we'll return null below.
             }
         }
diff --git a/bridge/src/android/graphics/BaseCanvas_Delegate.java b/bridge/src/android/graphics/BaseCanvas_Delegate.java
index a7e36f0..df28305 100644
--- a/bridge/src/android/graphics/BaseCanvas_Delegate.java
+++ b/bridge/src/android/graphics/BaseCanvas_Delegate.java
@@ -168,7 +168,7 @@
     /*package*/ static void nDrawPaint(long nativeCanvas, long paint) {
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Canvas.drawPaint is not supported.", null, null /*data*/);
+                "Canvas.drawPaint is not supported.", null,null, null /*data*/);
     }
 
     @LayoutlibDelegate
@@ -421,7 +421,7 @@
             long nativePaint) {
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Some canvas paths may not be drawn", null, null);
+                "Some canvas paths may not be drawn", null, null, null);
     }
 
     @LayoutlibDelegate
@@ -513,7 +513,7 @@
             int colorOffset, long nPaint) {
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Canvas.drawBitmapMesh is not supported.", null, null /*data*/);
+                "Canvas.drawBitmapMesh is not supported.", null, null, null /*data*/);
     }
 
     @LayoutlibDelegate
@@ -525,7 +525,7 @@
             int indexCount, long nPaint) {
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Canvas.drawVertices is not supported.", null, null /*data*/);
+                "Canvas.drawVertices is not supported.", null, null, null /*data*/);
     }
 
     @LayoutlibDelegate
@@ -574,7 +574,7 @@
             long paint) {
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Canvas.drawTextOnPath is not supported.", null, null /*data*/);
+                "Canvas.drawTextOnPath is not supported.", null, null, null /*data*/);
     }
 
     @LayoutlibDelegate
@@ -585,7 +585,7 @@
             int bidiFlags, long paint) {
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Canvas.drawTextOnPath is not supported.", null, null /*data*/);
+                "Canvas.drawTextOnPath is not supported.", null, null, null /*data*/);
     }
 
     // ---- Private delegate/helper methods ----
diff --git a/bridge/src/android/graphics/BidiRenderer.java b/bridge/src/android/graphics/BidiRenderer.java
index 204022d..1de2a45 100644
--- a/bridge/src/android/graphics/BidiRenderer.java
+++ b/bridge/src/android/graphics/BidiRenderer.java
@@ -223,7 +223,8 @@
 
     private static void logFontWarning() {
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_BROKEN,
-                "Some fonts could not be loaded. The rendering may not be perfect.", null, null);
+                "Some fonts could not be loaded. The rendering may not be perfect.", null, null,
+                null);
     }
 
     /**
diff --git a/bridge/src/android/graphics/BitmapFactory_Delegate.java b/bridge/src/android/graphics/BitmapFactory_Delegate.java
index 80c6761..b344451 100644
--- a/bridge/src/android/graphics/BitmapFactory_Delegate.java
+++ b/bridge/src/android/graphics/BitmapFactory_Delegate.java
@@ -93,7 +93,7 @@
                 bm = Bitmap_Delegate.createBitmap(is, bitmapCreateFlags, density);
             }
         } catch (IOException e) {
-            Bridge.getLog().error(null, "Failed to load image", e, null);
+            Bridge.getLog().error(null, "Failed to load image", e, null, null);
         }
 
         return bm;
diff --git a/bridge/src/android/graphics/BitmapShader_Delegate.java b/bridge/src/android/graphics/BitmapShader_Delegate.java
index 0e3e9a8..53b1db6 100644
--- a/bridge/src/android/graphics/BitmapShader_Delegate.java
+++ b/bridge/src/android/graphics/BitmapShader_Delegate.java
@@ -119,7 +119,7 @@
                 canvasMatrix = xform.createInverse();
             } catch (NoninvertibleTransformException e) {
                 Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
-                        "Unable to inverse matrix in BitmapShader", e, null /*data*/);
+                        "Unable to inverse matrix in BitmapShader", e, null, null /*data*/);
                 canvasMatrix = new AffineTransform();
             }
 
@@ -128,7 +128,7 @@
                 localMatrix = localMatrix.createInverse();
             } catch (NoninvertibleTransformException e) {
                 Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
-                        "Unable to inverse matrix in BitmapShader", e, null /*data*/);
+                        "Unable to inverse matrix in BitmapShader", e, null, null /*data*/);
                 localMatrix = new AffineTransform();
             }
 
diff --git a/bridge/src/android/graphics/Bitmap_Delegate.java b/bridge/src/android/graphics/Bitmap_Delegate.java
index 82e7918..7fc952d 100644
--- a/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -300,14 +300,14 @@
     /*package*/ static void nativeReconfigure(long nativeBitmap, int width, int height,
             int config, boolean isPremultiplied) {
         Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
-                "Bitmap.reconfigure() is not supported", null /*data*/);
+                "Bitmap.reconfigure() is not supported", null, null /*data*/);
     }
 
     @LayoutlibDelegate
     /*package*/ static boolean nativeCompress(long nativeBitmap, int format, int quality,
             OutputStream stream, byte[] tempStorage) {
         Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
-                "Bitmap.compress() is not supported", null /*data*/);
+                "Bitmap.compress() is not supported", null, null /*data*/);
         return true;
     }
 
@@ -427,14 +427,14 @@
     /*package*/ static void nativeCopyPixelsToBuffer(long nativeBitmap, Buffer dst) {
         // FIXME implement native delegate
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Bitmap.copyPixelsToBuffer is not supported.", null, null /*data*/);
+                "Bitmap.copyPixelsToBuffer is not supported.", null, null, null /*data*/);
     }
 
     @LayoutlibDelegate
     /*package*/ static void nativeCopyPixelsFromBuffer(long nb, Buffer src) {
         // FIXME implement native delegate
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Bitmap.copyPixelsFromBuffer is not supported.", null, null /*data*/);
+                "Bitmap.copyPixelsFromBuffer is not supported.", null, null, null /*data*/);
     }
 
     @LayoutlibDelegate
@@ -453,7 +453,7 @@
         // used during aidl call so really this should not be called.
         Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
                 "AIDL is not suppored, and therefore Bitmaps cannot be created from parcels.",
-                null /*data*/);
+                null, null /*data*/);
         return null;
     }
 
@@ -463,7 +463,7 @@
         // be called.
         Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
                 "AIDL is not suppored, and therefore Bitmaps cannot be written to parcels.",
-                null /*data*/);
+                null, null /*data*/);
         return false;
     }
 
@@ -481,7 +481,7 @@
         if (paint != null && paint.getMaskFilter() != null) {
             Bridge.getLog().fidelityWarning(LayoutLog.TAG_MASKFILTER,
                     "MaskFilter not supported in Bitmap.extractAlpha",
-                    null, null /*data*/);
+                    null, null, null /*data*/);
         }
 
         int alpha = paint != null ? paint.getAlpha() : 0xFF;
@@ -638,27 +638,27 @@
     @LayoutlibDelegate
     /*package*/ static boolean nativeIsSRGB(long nativeBitmap) {
         Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
-                "Color spaces are not supported", null /*data*/);
+                "Color spaces are not supported", null, null /*data*/);
         return false;
     }
 
     @LayoutlibDelegate
     /*package*/ static ColorSpace nativeComputeColorSpace(long nativePtr) {
         Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
-                "Color spaces are not supported", null /*data*/);
+                "Color spaces are not supported", null, null /*data*/);
         return null;
     }
 
     @LayoutlibDelegate
     /*package*/ static void nativeSetColorSpace(long nativePtr, long nativeColorSpace) {
         Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
-                "Color spaces are not supported", null /*data*/);
+                "Color spaces are not supported", null, null /*data*/);
     }
 
     @LayoutlibDelegate
     /*package*/ static boolean nativeIsSRGBLinear(long nativePtr) {
         Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
-                "Color spaces are not supported", null /*data*/);
+                "Color spaces are not supported", null, null /*data*/);
         return false;
     }
 
@@ -683,7 +683,7 @@
     @LayoutlibDelegate
     /*package*/ static HardwareBuffer nativeGetHardwareBuffer(long nativeBitmap) {
         Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
-                "HardwareBuffer is not supported", null /*data*/);
+                "HardwareBuffer is not supported", null, null /*data*/);
         return null;
     }
 
diff --git a/bridge/src/android/graphics/Canvas_Delegate.java b/bridge/src/android/graphics/Canvas_Delegate.java
index 1bdd8a6..afcb40c 100644
--- a/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/bridge/src/android/graphics/Canvas_Delegate.java
@@ -356,7 +356,7 @@
             assert false;
             Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_AFFINE,
                     "android.graphics.Canvas#setMatrix(android.graphics.Matrix) only " +
-                    "supports affine transformations.", null, null /*data*/);
+                    "supports affine transformations.", null, null, null /*data*/);
         }
     }
 
@@ -402,7 +402,7 @@
 
         if (canvasDelegate.mDrawFilter != null && !canvasDelegate.mDrawFilter.isSupported()) {
             Bridge.getLog().fidelityWarning(LayoutLog.TAG_DRAWFILTER,
-                    canvasDelegate.mDrawFilter.getSupportMessage(), null, null /*data*/);
+                    canvasDelegate.mDrawFilter.getSupportMessage(), null, null, null /*data*/);
         }
     }
 
diff --git a/bridge/src/android/graphics/FontFamily_Delegate.java b/bridge/src/android/graphics/FontFamily_Delegate.java
index 581220c..afcf9bd 100644
--- a/bridge/src/android/graphics/FontFamily_Delegate.java
+++ b/bridge/src/android/graphics/FontFamily_Delegate.java
@@ -185,7 +185,7 @@
         } catch (FileNotFoundException e) {
             Bridge.getLog().error(LayoutLog.TAG_BROKEN,
                     "Unable to load the list of fonts. Try re-installing the SDK Platform from the SDK Manager.",
-                    e, null);
+                    e, null, null);
         } finally {
             if (scanner != null) {
                 scanner.close();
@@ -270,12 +270,12 @@
                 }
                 Bridge.getLog().fidelityWarning(LayoutLog.TAG_BROKEN,
                         String.format("Unable to load font %1$s", relativePath),
-                        e, null);
+                        e, null, null);
             }
         } else {
             Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
                     "Only platform fonts located in " + SYSTEM_FONTS + "can be loaded.",
-                    null, null);
+                    null, null, null);
         }
 
         return null;
diff --git a/bridge/src/android/graphics/LinearGradient_Delegate.java b/bridge/src/android/graphics/LinearGradient_Delegate.java
index 8dcf374..7b544fe 100644
--- a/bridge/src/android/graphics/LinearGradient_Delegate.java
+++ b/bridge/src/android/graphics/LinearGradient_Delegate.java
@@ -127,7 +127,7 @@
                 canvasMatrix = xform.createInverse();
             } catch (java.awt.geom.NoninvertibleTransformException e) {
                 Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
-                        "Unable to inverse matrix in LinearGradient", e, null /*data*/);
+                        "Unable to inverse matrix in LinearGradient", e, null, null /*data*/);
                 canvasMatrix = new java.awt.geom.AffineTransform();
             }
 
@@ -136,7 +136,7 @@
                 localMatrix = localMatrix.createInverse();
             } catch (java.awt.geom.NoninvertibleTransformException e) {
                 Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
-                        "Unable to inverse matrix in LinearGradient", e, null /*data*/);
+                        "Unable to inverse matrix in LinearGradient", e, null, null /*data*/);
                 localMatrix = new java.awt.geom.AffineTransform();
             }
 
diff --git a/bridge/src/android/graphics/Matrix_Delegate.java b/bridge/src/android/graphics/Matrix_Delegate.java
index 64d8864..ca3cc96 100644
--- a/bridge/src/android/graphics/Matrix_Delegate.java
+++ b/bridge/src/android/graphics/Matrix_Delegate.java
@@ -600,7 +600,7 @@
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
                 "Matrix.setPolyToPoly is not supported.",
-                null, null /*data*/);
+                null, null, null /*data*/);
         return false;
     }
 
diff --git a/bridge/src/android/graphics/NinePatch_Delegate.java b/bridge/src/android/graphics/NinePatch_Delegate.java
index a6cd51e..ca2a9ca 100644
--- a/bridge/src/android/graphics/NinePatch_Delegate.java
+++ b/bridge/src/android/graphics/NinePatch_Delegate.java
@@ -80,7 +80,8 @@
             oos = new ObjectOutputStream(baos);
             oos.writeObject(chunk);
         } catch (IOException e) {
-            Bridge.getLog().error(null, "Failed to serialize NinePatchChunk.", e, null /*data*/);
+            Bridge.getLog().error(null, "Failed to serialize NinePatchChunk.", e, null,
+                    null /*data*/);
             return null;
         } finally {
             if (oos != null) {
@@ -120,11 +121,11 @@
                 }
             } catch (IOException e) {
                 Bridge.getLog().error(LayoutLog.TAG_BROKEN,
-                        "Failed to deserialize NinePatchChunk content.", e, null /*data*/);
+                        "Failed to deserialize NinePatchChunk content.", e, null, null /*data*/);
                 return null;
             } catch (ClassNotFoundException e) {
                 Bridge.getLog().error(LayoutLog.TAG_BROKEN,
-                        "Failed to deserialize NinePatchChunk class.", e, null /*data*/);
+                        "Failed to deserialize NinePatchChunk class.", e, null, null /*data*/);
                 return null;
             }
         }
diff --git a/bridge/src/android/graphics/Paint_Delegate.java b/bridge/src/android/graphics/Paint_Delegate.java
index df22d63..0512edf 100644
--- a/bridge/src/android/graphics/Paint_Delegate.java
+++ b/bridge/src/android/graphics/Paint_Delegate.java
@@ -230,7 +230,7 @@
             } else {
                 Bridge.getLog().fidelityWarning(LayoutLog.TAG_PATHEFFECT,
                         mPathEffect.getSupportMessage(),
-                        null, null /*data*/);
+                        null, null, null /*data*/);
             }
         }
 
@@ -456,14 +456,14 @@
             float radius, float dx, float dy, long colorSpaceHandle,
             long shadowColor) {
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Paint.setShadowLayer is not supported.", null, null /*data*/);
+                "Paint.setShadowLayer is not supported.", null, null, null /*data*/);
     }
 
     @LayoutlibDelegate
     /*package*/ static boolean nHasShadowLayer(long paint) {
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Paint.hasShadowLayer is not supported.", null, null /*data*/);
+                "Paint.hasShadowLayer is not supported.", null, null, null /*data*/);
         return false;
     }
 
@@ -848,7 +848,7 @@
         // Log warning if it's not supported.
         if (delegate.mColorFilter != null && !delegate.mColorFilter.isSupported()) {
             Bridge.getLog().fidelityWarning(LayoutLog.TAG_COLORFILTER,
-                    delegate.mColorFilter.getSupportMessage(), null, null /*data*/);
+                    delegate.mColorFilter.getSupportMessage(), null, null, null /*data*/);
         }
 
         return filter;
@@ -889,7 +889,7 @@
         // since none of those are supported, display a fidelity warning right away
         if (delegate.mMaskFilter != null && !delegate.mMaskFilter.isSupported()) {
             Bridge.getLog().fidelityWarning(LayoutLog.TAG_MASKFILTER,
-                    delegate.mMaskFilter.getSupportMessage(), null, null /*data*/);
+                    delegate.mMaskFilter.getSupportMessage(), null, null, null /*data*/);
         }
 
         return maskfilter;
@@ -985,7 +985,7 @@
             int contextStart, int contextLength, int flags, int offset, int cursorOpt) {
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Paint.getTextRunCursor is not supported.", null, null /*data*/);
+                "Paint.getTextRunCursor is not supported.", null, null, null /*data*/);
         return 0;
     }
 
@@ -994,7 +994,7 @@
             int contextStart, int contextEnd, int flags, int offset, int cursorOpt) {
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Paint.getTextRunCursor is not supported.", null, null /*data*/);
+                "Paint.getTextRunCursor is not supported.", null, null, null /*data*/);
         return 0;
     }
 
@@ -1003,7 +1003,7 @@
             int index, int count, float x, float y, long path) {
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Paint.getTextPath is not supported.", null, null /*data*/);
+                "Paint.getTextPath is not supported.", null, null, null /*data*/);
     }
 
     @LayoutlibDelegate
@@ -1011,7 +1011,7 @@
             int end, float x, float y, long path) {
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Paint.getTextPath is not supported.", null, null /*data*/);
+                "Paint.getTextPath is not supported.", null, null, null /*data*/);
     }
 
     @LayoutlibDelegate
@@ -1057,7 +1057,7 @@
     @LayoutlibDelegate
     /*package*/ static void nSetLetterSpacing(long nativePaint, float letterSpacing) {
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_TEXT_RENDERING,
-                "Paint.setLetterSpacing() not supported.", null, null);
+                "Paint.setLetterSpacing() not supported.", null, null, null);
         Paint_Delegate delegate = sManager.getDelegate(nativePaint);
         if (delegate == null) {
             return;
@@ -1086,7 +1086,7 @@
     @LayoutlibDelegate
     /*package*/ static void nSetFontFeatureSettings(long nativePaint, String settings) {
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_TEXT_RENDERING,
-                "Paint.setFontFeatureSettings() not supported.", null, null);
+                "Paint.setFontFeatureSettings() not supported.", null, null, null);
     }
 
     @LayoutlibDelegate
@@ -1136,7 +1136,7 @@
         }
         if (string.length() > 1) {
             Bridge.getLog().fidelityWarning(LayoutLog.TAG_TEXT_RENDERING,
-                    "Paint.hasGlyph() is not supported for ligatures.", null, null);
+                    "Paint.hasGlyph() is not supported for ligatures.", null, null, null);
             return false;
         }
 
diff --git a/bridge/src/android/graphics/PathMeasure_Delegate.java b/bridge/src/android/graphics/PathMeasure_Delegate.java
index 7f707c9..7276c45 100644
--- a/bridge/src/android/graphics/PathMeasure_Delegate.java
+++ b/bridge/src/android/graphics/PathMeasure_Delegate.java
@@ -80,7 +80,7 @@
     /*package*/ static boolean native_getPosTan(long native_instance, float distance, float pos[],
             float tan[]) {
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "PathMeasure.getPostTan is not supported.", null, null);
+                "PathMeasure.getPostTan is not supported.", null, null, null);
         return false;
     }
 
@@ -88,14 +88,14 @@
     /*package*/ static boolean native_getMatrix(long native_instance, float distance, long
             native_matrix, int flags) {
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "PathMeasure.getMatrix is not supported.", null, null);
+                "PathMeasure.getMatrix is not supported.", null, null, null);
         return false;
     }
 
     @LayoutlibDelegate
     /*package*/ static boolean native_nextContour(long native_instance) {
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "PathMeasure.nextContour is not supported.", null, null);
+                "PathMeasure.nextContour is not supported.", null, null, null);
         return false;
     }
 
diff --git a/bridge/src/android/graphics/Path_Delegate.java b/bridge/src/android/graphics/Path_Delegate.java
index 2f86026..df83d65 100644
--- a/bridge/src/android/graphics/Path_Delegate.java
+++ b/bridge/src/android/graphics/Path_Delegate.java
@@ -158,7 +158,7 @@
     @LayoutlibDelegate
     /*package*/ static boolean nIsConvex(long nPath) {
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                "Path.isConvex is not supported.", null, null);
+                "Path.isConvex is not supported.", null, null, null);
         return true;
     }
 
@@ -475,7 +475,7 @@
 
     @LayoutlibDelegate
     /*package*/ static boolean nOp(long nPath1, long nPath2, int op, long result) {
-        Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, "Path.op() not supported", null);
+        Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, "Path.op() not supported", null, null);
         return false;
     }
 
@@ -891,7 +891,7 @@
             assert false;
             Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_AFFINE,
                     "android.graphics.Path#transform() only " +
-                    "supports affine transformations.", null, null /*data*/);
+                    "supports affine transformations.", null, null, null /*data*/);
         }
 
         GeneralPath newPath = new GeneralPath();
diff --git a/bridge/src/android/graphics/RadialGradient_Delegate.java b/bridge/src/android/graphics/RadialGradient_Delegate.java
index a42d654..cd46b31 100644
--- a/bridge/src/android/graphics/RadialGradient_Delegate.java
+++ b/bridge/src/android/graphics/RadialGradient_Delegate.java
@@ -117,7 +117,7 @@
                 canvasMatrix = xform.createInverse();
             } catch (java.awt.geom.NoninvertibleTransformException e) {
                 Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
-                        "Unable to inverse matrix in RadialGradient", e, null /*data*/);
+                        "Unable to inverse matrix in RadialGradient", e, null, null /*data*/);
                 canvasMatrix = new java.awt.geom.AffineTransform();
             }
 
@@ -126,7 +126,7 @@
                 localMatrix = localMatrix.createInverse();
             } catch (java.awt.geom.NoninvertibleTransformException e) {
                 Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
-                        "Unable to inverse matrix in RadialGradient", e, null /*data*/);
+                        "Unable to inverse matrix in RadialGradient", e, null, null /*data*/);
                 localMatrix = new java.awt.geom.AffineTransform();
             }
 
diff --git a/bridge/src/android/graphics/Region_Delegate.java b/bridge/src/android/graphics/Region_Delegate.java
index edb7025..f1f44b9 100644
--- a/bridge/src/android/graphics/Region_Delegate.java
+++ b/bridge/src/android/graphics/Region_Delegate.java
@@ -438,7 +438,7 @@
         // used during aidl call so really this should not be called.
         Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
                 "AIDL is not suppored, and therefore Regions cannot be created from parcels.",
-                null /*data*/);
+                null, null /*data*/);
         return 0;
     }
 
@@ -449,7 +449,7 @@
         // be called.
         Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
                 "AIDL is not suppored, and therefore Regions cannot be written to parcels.",
-                null /*data*/);
+                null, null /*data*/);
         return false;
     }
 
diff --git a/bridge/src/android/graphics/SweepGradient_Delegate.java b/bridge/src/android/graphics/SweepGradient_Delegate.java
index d29307a..e02144d 100644
--- a/bridge/src/android/graphics/SweepGradient_Delegate.java
+++ b/bridge/src/android/graphics/SweepGradient_Delegate.java
@@ -112,7 +112,7 @@
                 canvasMatrix = xform.createInverse();
             } catch (java.awt.geom.NoninvertibleTransformException e) {
                 Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
-                        "Unable to inverse matrix in SweepGradient", e, null /*data*/);
+                        "Unable to inverse matrix in SweepGradient", e, null, null /*data*/);
                 canvasMatrix = new java.awt.geom.AffineTransform();
             }
 
@@ -121,7 +121,7 @@
                 localMatrix = localMatrix.createInverse();
             } catch (java.awt.geom.NoninvertibleTransformException e) {
                 Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
-                        "Unable to inverse matrix in SweepGradient", e, null /*data*/);
+                        "Unable to inverse matrix in SweepGradient", e, null, null /*data*/);
                 localMatrix = new java.awt.geom.AffineTransform();
             }
 
diff --git a/bridge/src/android/graphics/Typeface_Delegate.java b/bridge/src/android/graphics/Typeface_Delegate.java
index 4634864..35146f4 100644
--- a/bridge/src/android/graphics/Typeface_Delegate.java
+++ b/bridge/src/android/graphics/Typeface_Delegate.java
@@ -143,7 +143,7 @@
 
         if (newInstance != 0) {
             Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
-                    "nativeCreateFromTypefaceWithVariation is not supported", null, null);
+                    "nativeCreateFromTypefaceWithVariation is not supported", null, null, null);
         }
         return newInstance;
     }
@@ -266,14 +266,15 @@
                             FontResourcesParser.parse(blockParser, context.getResources());
                     typeface = Typeface.createFromResources(entry, context.getAssets(), path);
                 } catch (XmlPullParserException | IOException e) {
-                    Bridge.getLog().error(null, "Failed to parse file " + path, e, null /*data*/);
+                    Bridge.getLog().error(null, "Failed to parse file " + path, e, null, null /*data
+                    */);
                 } finally {
                     blockParser.ensurePopped();
                 }
             } else {
                 Bridge.getLog().error(LayoutLog.TAG_BROKEN,
                         String.format("File %s does not exist (or is not a file)", path),
-                        null /*data*/);
+                        null, null /*data*/);
             }
         } else {
             typeface = new Typeface.Builder(context.getAssets(), path, false, 0).build();
diff --git a/bridge/src/android/graphics/drawable/AnimatedVectorDrawable_Delegate.java b/bridge/src/android/graphics/drawable/AnimatedVectorDrawable_Delegate.java
index 5ad1dda..be78091 100644
--- a/bridge/src/android/graphics/drawable/AnimatedVectorDrawable_Delegate.java
+++ b/bridge/src/android/graphics/drawable/AnimatedVectorDrawable_Delegate.java
@@ -100,7 +100,7 @@
     /*package*/ static long nCreatePathDataPropertyHolder(long nativePtr, long startValuePtr,
             long endValuePtr) {
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, "AnimatedVectorDrawable path " +
-                "animations are not supported.", null, null);
+                "animations are not supported.", null, null, null);
         return 0;
     }
 
diff --git a/bridge/src/android/graphics/fonts/FontFamily_Builder_Delegate.java b/bridge/src/android/graphics/fonts/FontFamily_Builder_Delegate.java
index c9a4f04..32f1157 100644
--- a/bridge/src/android/graphics/fonts/FontFamily_Builder_Delegate.java
+++ b/bridge/src/android/graphics/fonts/FontFamily_Builder_Delegate.java
@@ -190,7 +190,7 @@
             return Font.createFont(Font.TRUETYPE_FONT, new ByteArrayInputStream(byteArray));
         } catch (Exception e) {
             Bridge.getLog().fidelityWarning(LayoutLog.TAG_BROKEN, "Unable to load font",
-                    e, null);
+                    e, null, null);
         }
 
         return null;
@@ -202,7 +202,7 @@
             return Font.createFont(Font.TRUETYPE_FONT, file);
         } catch (Exception e) {
             Bridge.getLog().fidelityWarning(LayoutLog.TAG_BROKEN, "Unable to load font",
-                    e, null);
+                    e, null, null);
         }
 
         return null;
diff --git a/bridge/src/android/util/PathParser_Delegate.java b/bridge/src/android/util/PathParser_Delegate.java
index 4010b67..96c093c 100644
--- a/bridge/src/android/util/PathParser_Delegate.java
+++ b/bridge/src/android/util/PathParser_Delegate.java
@@ -123,7 +123,7 @@
         if (length != to.mPathDataNodes.length) {
             Bridge.getLog().error(LayoutLog.TAG_BROKEN,
                     "Cannot interpolate path data with different lengths (from " + length + " to " +
-                            to.mPathDataNodes.length + ").", null);
+                            to.mPathDataNodes.length + ").", null, null);
             return false;
         }
         if (out.mPathDataNodes.length != length) {
diff --git a/bridge/src/android/view/BridgeInflater.java b/bridge/src/android/view/BridgeInflater.java
index f7e6ac2..f2cbfa0 100644
--- a/bridge/src/android/view/BridgeInflater.java
+++ b/bridge/src/android/view/BridgeInflater.java
@@ -296,7 +296,7 @@
 
             if (name == null) {
                 Bridge.getLog().error(LayoutLog.TAG_BROKEN, "Unable to inflate view tag without " +
-                  "class attribute", null);
+                  "class attribute", null, null);
                 // We weren't able to resolve the view so we just pass a mock View to be able to
                 // continue rendering.
                 view = new MockView(context, attrs);
@@ -323,7 +323,7 @@
                 // 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);
+                Bridge.getLog().error(LayoutLog.TAG_BROKEN, e.getMessage(), e, null, null);
             } else {
                 final Object lastContext = mConstructorArgs[0];
                 mConstructorArgs[0] = context;
@@ -383,7 +383,7 @@
                     return inflate(bridgeParser, root);
                 } catch (Exception e) {
                     Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
-                            "Failed to parse file " + path, e, null);
+                            "Failed to parse file " + path, e, null, null);
 
                     return null;
                 }
diff --git a/bridge/src/android/view/LayoutInflater_Delegate.java b/bridge/src/android/view/LayoutInflater_Delegate.java
index 3f364f9..66a94fa 100644
--- a/bridge/src/android/view/LayoutInflater_Delegate.java
+++ b/bridge/src/android/view/LayoutInflater_Delegate.java
@@ -107,7 +107,7 @@
                 final String value = attrs.getAttributeValue(null, ATTR_LAYOUT);
                 if (value == null || value.length() <= 0) {
                     Bridge.getLog().error(LayoutLog.TAG_BROKEN, "You must specify a layout in the"
-                            + " include tag: <include layout=\"@layout/layoutID\" />", null);
+                            + " include tag: <include layout=\"@layout/layoutID\" />", null, null);
                     LayoutInflater.consumeChildElements(parser);
                     return;
                 }
@@ -130,10 +130,10 @@
                 final String value = attrs.getAttributeValue(null, ATTR_LAYOUT);
                 if (value == null) {
                     Bridge.getLog().error(LayoutLog.TAG_BROKEN, "You must specify a layout in the"
-                            + " include tag: <include layout=\"@layout/layoutID\" />", null);
+                            + " include tag: <include layout=\"@layout/layoutID\" />", null, null);
                 } else {
                     Bridge.getLog().error(LayoutLog.TAG_BROKEN, "You must specify a valid layout "
-                            + "reference. The layout ID " + value + " is not valid.", null);
+                            + "reference. The layout ID " + value + " is not valid.", null, null);
                 }
             } else {
                 final XmlResourceParser childParser =
@@ -150,7 +150,7 @@
                     if (type != XmlPullParser.START_TAG) {
                         Bridge.getLog().error(LayoutLog.TAG_BROKEN,
                                 childParser.getPositionDescription() + ": No start tag found!",
-                                null);
+                                null, null);
                         LayoutInflater.consumeChildElements(parser);
                         return;
                     }
@@ -228,7 +228,7 @@
         } else {
             Bridge.getLog().error(LayoutLog.TAG_BROKEN,
                     "<include /> can only be used inside of a ViewGroup",
-                    null);
+                    null, null);
         }
 
         LayoutInflater.consumeChildElements(parser);
diff --git a/bridge/src/android/view/MenuInflater_Delegate.java b/bridge/src/android/view/MenuInflater_Delegate.java
index d16d851..83586a1 100644
--- a/bridge/src/android/view/MenuInflater_Delegate.java
+++ b/bridge/src/android/view/MenuInflater_Delegate.java
@@ -65,7 +65,7 @@
             // We suppress this error for AppCompat menus since we do not support them in the menu
             // editor yet.
             Bridge.getLog().warning(LayoutLog.TAG_BROKEN,
-                    "Action Bar Menu rendering may be incorrect.", null);
+                    "Action Bar Menu rendering may be incorrect.", null, null);
         }
 
     }
diff --git a/bridge/src/android/view/View_Delegate.java b/bridge/src/android/view/View_Delegate.java
index 0413f9a..9aae4ae 100644
--- a/bridge/src/android/view/View_Delegate.java
+++ b/bridge/src/android/view/View_Delegate.java
@@ -55,7 +55,7 @@
             // all the layout.
             thisView.draw_Original(canvas);
         } catch (Throwable t) {
-            Bridge.getLog().error(LayoutLog.TAG_BROKEN, "View draw failed", t, null);
+            Bridge.getLog().error(LayoutLog.TAG_BROKEN, "View draw failed", t, null, null);
         }
     }
 
@@ -67,7 +67,7 @@
             // all the layout.
             return thisView.draw_Original(canvas, parent, drawingTime);
         } catch (Throwable t) {
-            Bridge.getLog().error(LayoutLog.TAG_BROKEN, "View draw failed", t, null);
+            Bridge.getLog().error(LayoutLog.TAG_BROKEN, "View draw failed", t, null, null);
         }
         return false;
     }
@@ -79,7 +79,7 @@
             // all the layout.
             thisView.measure_Original(widthMeasureSpec, heightMeasureSpec);
         } catch (Throwable t) {
-            Bridge.getLog().error(LayoutLog.TAG_BROKEN, "View measure failed", t, null);
+            Bridge.getLog().error(LayoutLog.TAG_BROKEN, "View measure failed", t, null, null);
         }
     }
 
@@ -90,7 +90,7 @@
             // all the layout.
             thisView.layout_Original(l, t, r, b);
         } catch (Throwable th) {
-            Bridge.getLog().error(LayoutLog.TAG_BROKEN, "View layout failed", th, null);
+            Bridge.getLog().error(LayoutLog.TAG_BROKEN, "View layout failed", th, null, null);
         }
     }
 
diff --git a/bridge/src/android/view/shadow/AmbientShadowTriangulator.java b/bridge/src/android/view/shadow/AmbientShadowTriangulator.java
index 9e8e08b..630ec30 100644
--- a/bridge/src/android/view/shadow/AmbientShadowTriangulator.java
+++ b/bridge/src/android/view/shadow/AmbientShadowTriangulator.java
@@ -45,10 +45,10 @@
         } catch (IndexOutOfBoundsException|ArithmeticException mathError) {
             Bridge.getLog().warning(LayoutLog.TAG_INFO,  "Arithmetic error while drawing " +
                             "ambient shadow",
-                    mathError);
+                    null, mathError);
         } catch (Exception ex) {
             Bridge.getLog().warning(LayoutLog.TAG_INFO,  "Error while drawing shadow",
-                    ex);
+                    null, ex);
         }
     }
 
diff --git a/bridge/src/android/view/shadow/SpotShadowTriangulator.java b/bridge/src/android/view/shadow/SpotShadowTriangulator.java
index 075006f..854a4d5 100644
--- a/bridge/src/android/view/shadow/SpotShadowTriangulator.java
+++ b/bridge/src/android/view/shadow/SpotShadowTriangulator.java
@@ -60,10 +60,10 @@
         } catch (IndexOutOfBoundsException|ArithmeticException mathError) {
             Bridge.getLog().warning(LayoutLog.TAG_INFO,  "Arithmetic error while drawing " +
                             "spot shadow",
-                    mathError);
+                    null, mathError);
         } catch (Exception ex) {
             Bridge.getLog().warning(LayoutLog.TAG_INFO,  "Error while drawing shadow",
-                    ex);
+                    null, ex);
         }
     }
     /**
diff --git a/bridge/src/com/android/layoutlib/bridge/Bridge.java b/bridge/src/com/android/layoutlib/bridge/Bridge.java
index dfab618..0121e92 100644
--- a/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -126,17 +126,18 @@
      */
     private final static LayoutLog sDefaultLog = new LayoutLog() {
         @Override
-        public void error(String tag, String message, Object data) {
+        public void error(String tag, String message, Object viewCookie, Object data) {
             System.err.println(message);
         }
 
         @Override
-        public void error(String tag, String message, Throwable throwable, Object data) {
+        public void error(String tag, String message, Throwable throwable, Object viewCookie,
+                Object data) {
             System.err.println(message);
         }
 
         @Override
-        public void warning(String tag, String message, Object data) {
+        public void warning(String tag, String message, Object viewCookie, Object data) {
             System.out.println(message);
         }
     };
@@ -176,7 +177,7 @@
                 @Override
                 public void onInvokeV(String signature, boolean isNative, Object caller) {
                     sDefaultLog.error(null, "Missing Stub: " + signature +
-                            (isNative ? " (native)" : ""), null /*data*/);
+                            (isNative ? " (native)" : ""), null, null /*data*/);
 
                     if (debug.equalsIgnoreCase("throw")) {
                         // Throwing this exception doesn't seem that useful. It breaks
@@ -246,7 +247,7 @@
             if (log != null) {
                 log.error(LayoutLog.TAG_BROKEN,
                         "Failed to load com.android.internal.R from the layout library jar",
-                        throwable, null);
+                        throwable, null, null);
             }
             return false;
         }
diff --git a/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index a2538c2..d1d37fd 100644
--- a/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -511,11 +511,11 @@
                     }
                 } else {
                     Bridge.getLog().error(LayoutLog.TAG_BROKEN,
-                            String.format("File %s is missing!", path), null);
+                            String.format("File %s is missing!", path), null, null);
                 }
             } catch (XmlPullParserException e) {
                 Bridge.getLog().error(LayoutLog.TAG_BROKEN,
-                        "Failed to parse file " + path, e, null /*data*/);
+                        "Failed to parse file " + path, e, null, null /*data*/);
                 // we'll return null below.
             } finally {
                 mBridgeInflater.setResourceReference(null);
@@ -523,7 +523,7 @@
         } else {
             Bridge.getLog().error(LayoutLog.TAG_BROKEN,
                     String.format("Layout %s%s does not exist.", isPlatformLayout ? "android:" : "",
-                            layout.getName()), null);
+                            layout.getName()), null, null);
         }
 
         return Pair.of(null, Boolean.FALSE);
@@ -674,7 +674,7 @@
 
             if (style == null) {
                 Bridge.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE,
-                        "Failed to find style with " + resId, null);
+                        "Failed to find style with " + resId, null, null);
                 return null;
             }
         }
@@ -743,7 +743,7 @@
         } else if (set != null) {
             // really this should not be happening since its instantiated in Bridge
             Bridge.getLog().error(LayoutLog.TAG_BROKEN,
-                    "Parser is not a BridgeXmlBlockParser!", null);
+                    "Parser is not a BridgeXmlBlockParser!", null, null);
             return null;
         } else {
             // `set` is null, so there will be no values to resolve.
@@ -782,7 +782,8 @@
                 // This will happen if the user explicitly used a non existing int value for
                 // defStyleAttr or there's something wrong with the project structure/build.
                 Bridge.getLog().error(LayoutLog.TAG_RESOURCES_RESOLVE,
-                        "Failed to find the style corresponding to the id " + defStyleAttr, null);
+                        "Failed to find the style corresponding to the id " + defStyleAttr, null,
+                        null);
             } else {
                 // look for the style in the current theme, and its parent:
                 ResourceValue item = mRenderResources.findItemInTheme(defStyleAttribute);
@@ -825,21 +826,21 @@
                                     String.format(
                                             "Style with id 0x%x (resolved to '%s') does not exist.",
                                             defStyleRes, value.getName()),
-                                    null);
+                                    null, null);
                         }
                     } else {
                         Bridge.getLog().error(null,
                                 String.format(
                                         "Resource id 0x%x is not of type STYLE (instead %s)",
                                         defStyleRes, value.getResourceType().name()),
-                                null);
+                                null, null);
                     }
                 } else {
                     Bridge.getLog().error(null,
                             String.format(
                                     "Failed to find style with id 0x%x in current theme",
                                     defStyleRes),
-                            null);
+                            null, null);
                 }
             }
         }
@@ -941,7 +942,7 @@
                                 }
                                 Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_RESOLVE_THEME_ATTR,
                                         String.format("Failed to find '%s' in current theme.", val),
-                                        val);
+                                        null, val);
                             }
                         }
                     }
@@ -1952,7 +1953,7 @@
 
     @Override
     public File getObbDir() {
-        Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, "OBB not supported", null);
+        Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED, "OBB not supported", null, null);
         return null;
     }
 
diff --git a/bridge/src/com/android/layoutlib/bridge/android/support/DesignLibUtil.java b/bridge/src/com/android/layoutlib/bridge/android/support/DesignLibUtil.java
index 0c2ef8b..5f785f5 100644
--- a/bridge/src/com/android/layoutlib/bridge/android/support/DesignLibUtil.java
+++ b/bridge/src/com/android/layoutlib/bridge/android/support/DesignLibUtil.java
@@ -62,7 +62,7 @@
             invoke(getMethod(view.getClass(), "setTitle", CharSequence.class), view, title);
         } catch (ReflectionException e) {
             Bridge.getLog().warning(LayoutLog.TAG_INFO,
-                    "Error occurred while trying to set title.", e);
+                    "Error occurred while trying to set title.", null, e);
         }
     }
 }
diff --git a/bridge/src/com/android/layoutlib/bridge/android/support/DrawerLayoutUtil.java b/bridge/src/com/android/layoutlib/bridge/android/support/DrawerLayoutUtil.java
index 1124a21..c41bcae 100644
--- a/bridge/src/com/android/layoutlib/bridge/android/support/DrawerLayoutUtil.java
+++ b/bridge/src/com/android/layoutlib/bridge/android/support/DrawerLayoutUtil.java
@@ -60,7 +60,7 @@
                     gravity);
         } catch (ReflectionException e) {
             Bridge.getLog().error(LayoutLog.TAG_BROKEN, "Unable to open navigation drawer",
-                    getCause(e), null);
+                    getCause(e), null, null);
         }
     }
 }
diff --git a/bridge/src/com/android/layoutlib/bridge/android/support/FragmentTabHostUtil.java b/bridge/src/com/android/layoutlib/bridge/android/support/FragmentTabHostUtil.java
index da2d3ee..c77cb57 100644
--- a/bridge/src/com/android/layoutlib/bridge/android/support/FragmentTabHostUtil.java
+++ b/bridge/src/com/android/layoutlib/bridge/android/support/FragmentTabHostUtil.java
@@ -60,7 +60,7 @@
 
         if (fragmentManager == null) {
             Bridge.getLog().error(LayoutLog.TAG_BROKEN,
-                    "Unable to find FragmentManager.", null);
+                    "Unable to find FragmentManager.", null, null);
             return;
         }
 
@@ -71,7 +71,7 @@
         } catch (ReflectionException e) {
             Throwable cause = getCause(e);
             Bridge.getLog().error(LayoutLog.TAG_BROKEN,
-                    "Error occurred while trying to setup FragmentTabHost.", cause, null);
+                    "Error occurred while trying to setup FragmentTabHost.", cause, null, null);
         }
     }
 }
diff --git a/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java b/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java
index 894937c..6fc8009 100644
--- a/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java
+++ b/bridge/src/com/android/layoutlib/bridge/android/support/RecyclerViewUtil.java
@@ -73,7 +73,7 @@
         } catch (ReflectionException e) {
             Throwable cause = getCause(e);
             Bridge.getLog().error(LayoutLog.TAG_BROKEN,
-                    "Error occurred while trying to setup RecyclerView.", cause, null);
+                    "Error occurred while trying to setup RecyclerView.", cause, null, null);
         }
     }
 
diff --git a/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java b/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java
index 617a302..ab88f15 100644
--- a/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java
+++ b/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java
@@ -119,7 +119,7 @@
             getContentRoot().setId(id.content);
         } catch (Exception e) {
             Bridge.getLog().warning(LayoutLog.TAG_BROKEN,
-                    "Failed to load AppCompat ActionBar with unknown error.", e);
+                    "Failed to load AppCompat ActionBar with unknown error.", null, e);
         }
     }
 
diff --git a/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java b/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
index 332a861..3a5f633 100644
--- a/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
+++ b/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
@@ -259,7 +259,7 @@
                     Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
                             "Theme attribute @android:" + attr +
                                     " does not reference a color, instead is '" +
-                                    resource.getValue() + "'.", resource);
+                                    resource.getValue() + "'.", null, resource);
                 }
             }
         }
diff --git a/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java b/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
index 4aa3a58..f58443a 100644
--- a/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
+++ b/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
@@ -91,7 +91,7 @@
 
         if (icons.size() != 2 || clockView == null) {
             Bridge.getLog().error(LayoutLog.TAG_BROKEN, "Unable to initialize statusbar", null,
-                    null);
+                    null, null);
             return;
         }
 
@@ -127,10 +127,10 @@
                         Drawable.createFromXml(mContext.getResources(), parser));
             } catch (XmlPullParserException e) {
                 Bridge.getLog().error(LayoutLog.TAG_BROKEN, "Unable to draw wifi icon", e,
-                        null);
+                        null, null);
             } catch (IOException e) {
                 Bridge.getLog().error(LayoutLog.TAG_BROKEN, "Unable to draw wifi icon", e,
-                        null);
+                        null, null);
             }
         }
 
diff --git a/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java b/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
index c4634f5..959ba77 100644
--- a/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
+++ b/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
@@ -917,7 +917,7 @@
             bounds.x += latestTransform.getTranslateX() - originalTransform.getTranslateX();
             bounds.y += latestTransform.getTranslateY() - originalTransform.getTranslateY();
         } catch (NoninvertibleTransformException e) {
-            Bridge.getLog().warning(null, "Non invertible transformation", null);
+            Bridge.getLog().warning(null, "Non invertible transformation", null, null);
         }
         return bounds;
     }
diff --git a/bridge/src/com/android/layoutlib/bridge/impl/PorterDuffUtility.java b/bridge/src/com/android/layoutlib/bridge/impl/PorterDuffUtility.java
index 70e2eb1..dcbd272 100644
--- a/bridge/src/com/android/layoutlib/bridge/impl/PorterDuffUtility.java
+++ b/bridge/src/com/android/layoutlib/bridge/impl/PorterDuffUtility.java
@@ -48,7 +48,7 @@
             return PorterDuff.intToMode(porterDuffMode);
         }
         Bridge.getLog().error(LayoutLog.TAG_BROKEN,
-                String.format("Unknown PorterDuff.Mode: %1$d", porterDuffMode), null);
+                String.format("Unknown PorterDuff.Mode: %1$d", porterDuffMode), null, null);
         assert false;
         return Mode.SRC_OVER;
     }
@@ -99,7 +99,7 @@
             default:
                 Bridge.getLog().fidelityWarning(LayoutLog.TAG_BROKEN,
                         String.format("Unsupported PorterDuff Mode: %1$s", mode.name()),
-                        null, null /*data*/);
+                        null, null, null /*data*/);
 
                 return AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha1);
         }
diff --git a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index 7cfe4c0..e7904ab 100644
--- a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -300,14 +300,14 @@
                 if (!params.isRtlSupported()) {
                     Bridge.getLog().warning(LayoutLog.TAG_RTL_NOT_ENABLED,
                             "You are using a right-to-left " +
-                                    "(RTL) locale but RTL is not enabled", null);
+                                    "(RTL) locale but RTL is not enabled", null, null);
                 } else if (params.getSimulatedPlatformVersion() !=0 &&
                         params.getSimulatedPlatformVersion() < 17) {
                     // This will render ok because we are using the latest layoutlib but at least
                     // warn the user that this might fail in a real device.
                     Bridge.getLog().warning(LayoutLog.TAG_RTL_NOT_SUPPORTED, "You are using a " +
                             "right-to-left " +
-                            "(RTL) locale but RTL is not supported for API level < 17", null);
+                            "(RTL) locale but RTL is not supported for API level < 17", null, null);
                 }
             }
 
diff --git a/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java b/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
index d3b934f..8e2ecd6 100644
--- a/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
+++ b/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
@@ -203,13 +203,13 @@
             }
         } catch (XmlPullParserException e) {
             Bridge.getLog().error(LayoutLog.TAG_BROKEN,
-                    "Failed to configure parser for " + value, e, null /*data*/);
+                    "Failed to configure parser for " + value, e, null,null /*data*/);
             // we'll return null below.
         } catch (Exception e) {
             // this is an error and not warning since the file existence is
             // checked before attempting to parse it.
             Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
-                    "Failed to parse file " + value, e, null /*data*/);
+                    "Failed to parse file " + value, e, null, null /*data*/);
 
             return null;
         }
@@ -333,7 +333,7 @@
             } catch (IOException e) {
                 // failed to read the file, we'll return null below.
                 Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
-                        "Failed to load " + stringValue, e, null /*data*/);
+                        "Failed to load " + stringValue, e, null, null /*data*/);
             }
 
             return null;
@@ -349,7 +349,8 @@
                         context.putUserData(KEY_GET_DRAWABLE, visitedValues);
                     }
                     if (!visitedValues.add(value)) {
-                        Bridge.getLog().error(null, "Cyclic dependency in " + stringValue, null);
+                        Bridge.getLog().error(null, "Cyclic dependency in " + stringValue, null,
+                                null);
                         return null;
                     }
 
@@ -364,7 +365,7 @@
                 // this is an error and not warning since the file existence is checked before
                 // attempting to parse it.
                 Bridge.getLog().error(null, "Failed to parse file " + stringValue, e,
-                        null /*data*/);
+                        null, null /*data*/);
             }
 
             return null;
@@ -393,7 +394,7 @@
                 } catch (IOException e) {
                     // we'll return null below
                     Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
-                            "Failed to load " + stringValue, e, null /*data*/);
+                            "Failed to load " + stringValue, e, null, null /*data*/);
                 }
             }
         }
@@ -636,7 +637,7 @@
                                 String.format(
                                         "Dimension \"%1$s\" in attribute \"%2$s\" is missing unit!",
                                         value, attribute),
-                                null);
+                                null, null);
                     }
                     return true;
                 }
diff --git a/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterHelper.java b/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterHelper.java
index f830b07..76c5942 100644
--- a/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterHelper.java
+++ b/bridge/src/com/android/layoutlib/bridge/impl/binding/AdapterHelper.java
@@ -95,7 +95,7 @@
                             if (value.getClass() != ViewAttribute.TEXT.getAttributeClass()) {
                                 Bridge.getLog().error(LayoutLog.TAG_BROKEN, String.format(
                                         "Wrong Adapter Item value class for TEXT. Expected String, got %s",
-                                        value.getClass().getName()), null);
+                                        value.getClass().getName()), null, null);
                             } else {
                                 tv.setText((String) value);
                             }
@@ -115,7 +115,7 @@
                             if (value.getClass() != ViewAttribute.IS_CHECKED.getAttributeClass()) {
                                 Bridge.getLog().error(LayoutLog.TAG_BROKEN, String.format(
                                         "Wrong Adapter Item value class for IS_CHECKED. Expected Boolean, got %s",
-                                        value.getClass().getName()), null);
+                                        value.getClass().getName()), null, null);
                             } else {
                                 cb.setChecked((Boolean) value);
                             }
@@ -135,7 +135,7 @@
                             if (value.getClass() != ViewAttribute.SRC.getAttributeClass()) {
                                 Bridge.getLog().error(LayoutLog.TAG_BROKEN, String.format(
                                         "Wrong Adapter Item value class for SRC. Expected Boolean, got %s",
-                                        value.getClass().getName()), null);
+                                        value.getClass().getName()), null, null);
                             } else {
                                 // FIXME
                             }
diff --git a/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTestBase.java b/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTestBase.java
index aad94a1..77c6d1a 100644
--- a/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTestBase.java
+++ b/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTestBase.java
@@ -416,7 +416,7 @@
         if (sLayoutLibLog == null) {
             sLayoutLibLog = new LayoutLog() {
                 @Override
-                public void warning(String tag, String message, Object data) {
+                public void warning(String tag, String message, Object cookie, Object data) {
                     System.out.println("Warning " + tag + ": " + message);
                     failWithMsg(message);
                 }
@@ -433,13 +433,14 @@
                 }
 
                 @Override
-                public void error(String tag, String message, Object data) {
+                public void error(String tag, String message, Object cookie, Object data) {
                     System.out.println("Error " + tag + ": " + message);
                     failWithMsg(message);
                 }
 
                 @Override
-                public void error(String tag, String message, Throwable throwable, Object data) {
+                public void error(String tag, String message, Throwable throwable, Object cookie,
+                        Object data) {
                     System.out.println("Error " + tag + ": " + message);
                     if (throwable != null) {
                         throwable.printStackTrace();
diff --git a/remote/client/src/com/android/layoutlib/bridge/remote/client/adapters/RemoteLayoutLogAdapter.java b/remote/client/src/com/android/layoutlib/bridge/remote/client/adapters/RemoteLayoutLogAdapter.java
index c5dbfab..23d36bc 100644
--- a/remote/client/src/com/android/layoutlib/bridge/remote/client/adapters/RemoteLayoutLogAdapter.java
+++ b/remote/client/src/com/android/layoutlib/bridge/remote/client/adapters/RemoteLayoutLogAdapter.java
@@ -37,8 +37,8 @@
     }
 
     @Override
-    public void warning(String tag, String message, Serializable data) {
-        mLog.warning(tag, message, null);
+    public void warning(String tag, String message, Object viewCookie, Serializable data) {
+        mLog.warning(tag, message, viewCookie, null);
     }
 
     @Override
@@ -48,12 +48,12 @@
     }
 
     @Override
-    public void error(String tag, String message, Serializable data) {
-        mLog.error(tag, message, null);
+    public void error(String tag, String message, Object viewCookie, Serializable data) {
+        mLog.error(tag, message, viewCookie, null);
     }
 
     @Override
-    public void error(String tag, String message, Throwable throwable, Serializable data) {
-        mLog.error(tag, message, throwable, null);
+    public void error(String tag, String message, Throwable throwable, Object viewCookie, Serializable data) {
+        mLog.error(tag, message, throwable, viewCookie, null);
     }
 }
diff --git a/remote/common/src/com/android/layout/remote/api/RemoteLayoutLog.java b/remote/common/src/com/android/layout/remote/api/RemoteLayoutLog.java
index c3b5c61..01add53 100644
--- a/remote/common/src/com/android/layout/remote/api/RemoteLayoutLog.java
+++ b/remote/common/src/com/android/layout/remote/api/RemoteLayoutLog.java
@@ -31,9 +31,10 @@
      *
      * @param tag a tag describing the type of the warning
      * @param message the message of the warning
+     * @param viewCookie optional cookie of the view associated to this error
      * @param data an optional data bundle that the client can use to improve the warning display.
      */
-    void warning(String tag, String message, Serializable data) throws RemoteException;
+    void warning(String tag, String message, Object viewCookie, Serializable data) throws RemoteException;
 
     /**
      * Logs a fidelity warning.
@@ -55,9 +56,10 @@
      *
      * @param tag a tag describing the type of the error
      * @param message the message of the error
+     * @param viewCookie optional cookie of the view associated to this error
      * @param data an optional data bundle that the client can use to improve the error display.
      */
-    void error(String tag, String message, Serializable data) throws RemoteException;
+    void error(String tag, String message, Object viewCookie, Serializable data) throws RemoteException;
 
     /**
      * Logs an error, and the {@link Throwable} that triggered it.
@@ -65,8 +67,9 @@
      * @param tag a tag describing the type of the error
      * @param message the message of the error
      * @param throwable the Throwable that triggered the error
+     * @param viewCookie optional cookie of the view associated to this error
      * @param data an optional data bundle that the client can use to improve the error display.
      */
-    void error(String tag, String message, Throwable throwable, Serializable data)
+    void error(String tag, String message, Throwable throwable, Object viewCookie, Serializable data)
             throws RemoteException;
 }
diff --git a/remote/server/src/com/android/layoutlib/bridge/remote/server/adapters/RemoteLayoutLogAdapter.java b/remote/server/src/com/android/layoutlib/bridge/remote/server/adapters/RemoteLayoutLogAdapter.java
index 6878d46..90da083 100644
--- a/remote/server/src/com/android/layoutlib/bridge/remote/server/adapters/RemoteLayoutLogAdapter.java
+++ b/remote/server/src/com/android/layoutlib/bridge/remote/server/adapters/RemoteLayoutLogAdapter.java
@@ -30,9 +30,9 @@
     }
 
     @Override
-    public void warning(String tag, String message, Object data) {
+    public void warning(String tag, String message, Object viewCookie, Object data) {
         try {
-            mLog.warning(tag, message, null);
+            mLog.warning(tag, message, viewCookie, null);
         } catch (RemoteException e) {
             throw new RuntimeException(e);
         }
@@ -49,18 +49,19 @@
     }
 
     @Override
-    public void error(String tag, String message, Object data) {
+    public void error(String tag, String message, Object viewCookie, Object data) {
         try {
-            mLog.error(tag, message, null);
+            mLog.error(tag, message, viewCookie, null);
         } catch (RemoteException e) {
             throw new RuntimeException(e);
         }
     }
 
     @Override
-    public void error(String tag, String message, Throwable throwable, Object data) {
+    public void error(String tag, String message, Throwable throwable, Object viewCookie,
+            Object data) {
         try {
-            mLog.error(tag, message, throwable, null);
+            mLog.error(tag, message, throwable, viewCookie, null);
         } catch (RemoteException e) {
             throw new RuntimeException(e);
         }
diff --git a/studio-custom-widgets/src/com/android/tools/idea/editors/theme/widgets/ErrorCatcher.java b/studio-custom-widgets/src/com/android/tools/idea/editors/theme/widgets/ErrorCatcher.java
index ecf39b3..519b127 100644
--- a/studio-custom-widgets/src/com/android/tools/idea/editors/theme/widgets/ErrorCatcher.java
+++ b/studio-custom-widgets/src/com/android/tools/idea/editors/theme/widgets/ErrorCatcher.java
@@ -61,7 +61,7 @@
                     resolveSize(child.getMeasuredHeight(), heightMeasureSpec));
         } catch (Throwable t) {
             Bridge.getLog().warning(LayoutLog.TAG_BROKEN, "Failed to do onMeasure for view " +
-                    child.getClass().getCanonicalName(), t);
+                    child.getClass().getCanonicalName(), null, t);
             setMeasuredDimension(resolveSize(0, widthMeasureSpec),
                     resolveSize(0, heightMeasureSpec));
         }
@@ -73,7 +73,7 @@
             return super.drawChild(canvas, child, drawingTime);
         } catch (Throwable t) {
             Bridge.getLog().warning(LayoutLog.TAG_BROKEN, "Failed to draw for view " +
-                    child.getClass().getCanonicalName(), t);
+                    child.getClass().getCanonicalName(), null, t);
         }
 
         return false;
@@ -88,7 +88,7 @@
             child.layout(0, 0, child.getMeasuredWidth(), child.getMeasuredHeight());
         } catch (Throwable e) {
             Bridge.getLog().warning(LayoutLog.TAG_BROKEN, "Failed to do onLayout for view " +
-                    child.getClass().getCanonicalName(), e);
+                    child.getClass().getCanonicalName(), null, e);
         }
     }
 }
diff --git a/validator/Android.bp b/validator/Android.bp
new file mode 100644
index 0000000..e55a433
--- /dev/null
+++ b/validator/Android.bp
@@ -0,0 +1,40 @@
+//
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+java_library_host {
+    name: "layoutlib-validator",
+
+    srcs: ["src/**/*.java"],
+    java_resource_dirs: ["resources"],
+
+    libs: [
+        "tools-common-prebuilt",
+        "temp_layoutlib",
+        "layoutlib-common",
+        "guava",
+    ],
+
+    static_libs: [
+        "atf-prebuilt-jars",
+        "hamcrest",
+        "jsoup-1.6.3",
+        "protobuf-lite",
+    ],
+
+    dist: {
+        targets: ["layoutlib"],
+    },
+}
diff --git a/validator/resources/strings.properties b/validator/resources/strings.properties
new file mode 100644
index 0000000..380a727
--- /dev/null
+++ b/validator/resources/strings.properties
@@ -0,0 +1,133 @@
+
+#
+# Copyright (C) 2020 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+actionable = actionable
+button_item_type = button
+check_title_accessibility_traversal = Traversal order
+check_title_class_name_not_supported = Unsupported item type
+check_title_clickablespan = Link
+check_title_duplicate_clickable_bounds = Clickable items
+check_title_duplicate_speakable_text = Item descriptions
+check_title_editable_content_desc = Editable item label
+check_title_image_contrast = Image contrast
+check_title_item_exposed = Exposed items
+check_title_link_test = Link text
+check_title_reading_score = Readability
+check_title_redundant_description = Item type label
+check_title_speakable_text_present = Item label
+check_title_text_contrast = Text contrast
+check_title_text_style = Text Style
+check_title_touch_target_size = Touch target
+check_view_banned_word = Banned word
+clickable = clickable
+clickable_and_long_clickable = clickable and long clickable
+italic_text = italic
+italic_underline_text = italic and underline
+long_clickable = long clickable
+non_clickable = non-clickable
+question_id_message_confirm_foreground_background_colors = Are the detected foreground and background colors correct?
+question_id_message_provide_background_color = What is the correct background color?
+question_id_message_provide_foreground_color = What is the correct foreground color?
+question_message_identify_unexposed_items = Select regions of the screen with unidentified items.
+question_message_screen_has_unexposed_items = Does this screen contain important items that are not outlined?
+question_option_message_background_incorrect = Background incorrect
+question_option_message_both_correct = Both correct
+question_option_message_both_incorrect = Foreground and background incorrect
+question_option_message_foreground_incorrect = Foreground incorrect
+question_option_message_unknown = Unknown
+result_message_addendum_against_scrollable_edge = This item may be only partially visible within a scrollable container.
+result_message_addendum_clickable_ancestor = A parent container may be handling touch events for this item. If selecting the larger container performs the same action as selecting this item, consider defining this item as not clickable. If a different action is performed, consider increasing the size of this item.
+result_message_addendum_clipped_by_ancestor = A parent container may be clipping the size of this item, which has a drawing area of <tt>%1$ddp</tt> x <tt>%2$ddp</tt>. Consider increasing the size of this item\'s clipping ancestor, or allowing a larger parent container to handle actions on behalf of this item.
+result_message_addendum_opacity_description = Its actual opacity is %1$.2f%%.
+result_message_addendum_touch_delegate = A <tt>TouchDelegate</tt> has been detected on one of this item\'s ancestors. This message can be ignored if the delegate is of sufficient size and handles touches for this item.
+result_message_addendum_touch_delegate_with_hit_rect = A <tt>TouchDelegate</tt> with size <tt>%1$ddp</tt> x <tt>%2$ddp</tt> has been detected for this item. Consider increasing the size of its hit <tt>Rect</tt>.
+result_message_addendum_view_potentially_obscured = This item may be obscured by other on-screen content. Consider manually testing this item\'s contrast.
+result_message_ai4design_contrast_not_sufficient = The item\'s text contrast ratio is %1$.2f.Consider increasing this item\'s text contrast ratio to %2$.2f or greater.
+result_message_ai4design_text_not_determined = The item\'s text could not be determined.
+result_message_background_must_be_opaque = This items\'s background color is not opaque.
+result_message_banned_word = This item\'s text may contain an inappropriate word, "<tt>%1$s</tt>"
+result_message_brief_banned_word = Consider removing inappropriate words from this item\'s text
+result_message_brief_content_desc_contains_redundant_word = This item\'s <tt>android:contentDescription</tt> might contain unnecessary text.
+result_message_brief_image_contrast_not_sufficient = Consider increasing the contrast ratio between this image\'s foreground and background.
+result_message_brief_is_unexposed_item_screen_region = Consider exposing items in this region to accessibility services.
+result_message_brief_link_text_not_descriptive = Consider using more descriptive text in the link.
+result_message_brief_low_reading_score = This text may have a low readability score.
+result_message_brief_same_speakable_text = Multiple items have the same description.
+result_message_brief_same_view_bounds = Multiple %1$s items share this location on the screen.
+result_message_brief_small_touch_target = Consider making this clickable item larger.
+result_message_brief_styled_text = Consider removing %1$s styling on longer passages of text.
+result_message_brief_text_contrast_not_sufficient = Consider increasing this item\'s text foreground to background contrast ratio.
+result_message_brief_unpredictable_traversal = Traversal behavior with screen readers may be unpredictable.
+result_message_class_name_is_empty = This item\'s type may not be reported to accessibility services. Consider using a type defined by the Android SDK.
+result_message_class_name_is_unknown = This item\'s type could not be determined.
+result_message_class_name_not_supported_brief = This item\'s type may not be supported.
+result_message_class_name_not_supported_detail = This item\'s type <tt>%1$s</tt> may not be resolvable by accessibility services. Consider using a type defined by the Android SDK.
+result_message_clickablespan_no_determined_type = This item\'s type is undetermined.
+result_message_content_desc_contains_redundant_word = This item\'s <tt>android:contentDescription</tt>, \"<tt>%1$s</tt>\" contains the item type \"<tt>%2$s</tt>\".
+result_message_content_desc_ends_with_view_type = This item\'s <tt>android:contentDescription</tt>, \"<tt>%1$s</tt>\" ends with the item\'s type.
+result_message_could_not_get_background_color = This item\'s background color could not be determined.
+result_message_could_not_get_text_color = This item\'s text color could not be determined.
+result_message_customized_small_touch_target_height = This item\'s height is <tt>%1$ddp</tt>. Consider increasing the height of this touch target to at least the configured minimum height of <tt>%2$ddp</tt>.
+result_message_customized_small_touch_target_width = This item\'s width is <tt>%1$ddp</tt>. Consider increasing the width of this touch target to at least the configured minimum width of <tt>%2$ddp</tt>.
+result_message_customized_small_touch_target_width_and_height = This item\'s size is <tt>%1$ddp</tt> x <tt>%2$ddp</tt>. Consider increasing this touch target to at least the configured minimum size of <tt>%3$ddp</tt> x <tt>%4$ddp</tt>.
+result_message_disruptive_announcement = A disruptive accessibility announcement has been used.
+result_message_editable_textview_content_desc = This editable <tt>TextView</tt> has an <tt>android:contentDescription</tt>. A screen reader may read this attribute instead of the editable content when the user is navigating.
+result_message_english_locale_only = This check only runs on devices with locales set to English.
+result_message_has_unexposed_items = This screen may have items that are not exposed to accessibility services.
+result_message_image_contrast_not_sufficient = The image\'s contrast ratio is %1$.2f. This ratio is based on an estimated foreground color of <tt>#%3$06X</tt> and an estimated background color of <tt>#%4$06X</tt>. Consider increasing this ratio to %2$.2f or greater.
+result_message_image_customized_contrast_not_sufficient = The image\'s contrast ratio is %1$.2f. This ratio is based on an estimated foreground color of <tt>#%3$06X</tt> and an estimated background color of <tt>#%4$06X</tt>. Consider increasing this ratio to the configured ratio of %2$.2f or greater.
+result_message_is_unexposed_item_screen_region = The region with on-screen location <tt>%1$s</tt> contains at least one item that is not exposed to accessibility services.
+result_message_item_exposed_needs_manual_assessment = This screen needs manual inspection to ensure all items are exposed to accessibility services.
+result_message_link_text_not_descriptive = The link text \"<tt>%1$s</tt>\" may not independently convey the link\'s purpose.
+result_message_low_reading_score = This item\'s text has an approximate readability score of %1$.0f, which is lower than the recommended score of %2$.0f. Consider using simpler words or sentences to make the text easier to read.
+result_message_missing_speakable_text = This item may not have a label readable by screen readers.
+result_message_no_content_desc = This item has no <tt>android:contentDescription</tt>.
+result_message_no_screencapture = Screen capture data could not be obtained.
+result_message_no_typeface_info = This item\'s typeface could not be determined.
+result_message_not_clickable = This view is not clickable.
+result_message_not_editable_textview = This item is not an editable <tt>TextView</tt>.
+result_message_not_enabled = This item isn\'t enabled.
+result_message_not_imageview = This item is not an <tt>ImageView</tt>.
+result_message_not_important_for_accessibility = This item was not found to be important for accessibility.
+result_message_not_text_view = This item is not a <tt>TextView</tt>.
+result_message_not_visible = This item is not visible.
+result_message_same_speakable_text = This %1$s item\'s speakable text: \"<tt>%2$s</tt>\" is identical to that of %3$d other item(s).
+result_message_same_view_bounds = This %1$s item has the same on-screen location (<tt>%2$s</tt>) as %3$d other item(s) with those properties.
+result_message_screencapture_data_hidden = Screen capture information for this item was hidden.
+result_message_screencapture_uniform_color = Screen capture has a uniform color.
+result_message_sdk_version_not_applicable = This check is not applicable on devices running Android %1$s and above.
+result_message_short_text = This item\'s text is too short to be evaluated.
+result_message_should_not_focus = This item would not be focused by a screen reader.
+result_message_small_touch_target_height = This item\'s height is <tt>%1$ddp</tt>. Consider making the height of this touch target <tt>%2$ddp</tt> or larger.
+result_message_small_touch_target_width = This item\'s width is <tt>%1$ddp</tt>. Consider making the width of this touch target <tt>%2$ddp</tt> or larger.
+result_message_small_touch_target_width_and_height = This item\'s size is <tt>%1$ddp</tt> x <tt>%2$ddp</tt>. Consider making this touch target <tt>%3$ddp</tt> wide and <tt>%4$ddp</tt> high or larger.
+result_message_speakable_text = This %1$s item also has speakable text: \"<tt>%2$s</tt>\".
+result_message_styled_text = This item may use %1$s font for a long passage of text. Consider removing the style from the font to improve readability.
+result_message_text_must_be_opaque = This item\'s text color is not opaque.
+result_message_textview_contrast_not_sufficient = The item\'s text contrast ratio is %1$.2f. This ratio is based on a text color of <tt>#%2$06X</tt> and background color of <tt>#%3$06X</tt>. Consider increasing this item\'s text contrast ratio to %4$.2f or greater.
+result_message_textview_empty = This <tt>TextView</tt> is empty.
+result_message_textview_heuristic_contrast_not_sufficient = The item\'s text contrast ratio is %1$.2f. This ratio is based on an estimated foreground color of <tt>#%2$06X</tt> and an estimated background color of <tt>#%3$06X</tt>. Consider using colors that result in a contrast ratio greater than %4$.2f for small text, or %5$.2f for large text.
+result_message_textview_heuristic_contrast_not_sufficient_confirmed = The item\'s text contrast ratio is %1$.2f. This ratio is based on the provided foreground color of <tt>#%2$06X</tt> and provided background color of <tt>#%3$06X</tt>. Consider using colors that result in a contrast ratio greater than %4$.2f for small text, or %5$.2f for large text.
+result_message_textview_heuristic_customized_contrast_not_sufficient = The item\'s text contrast ratio is %1$.2f. This ratio is based on an estimated foreground color of <tt>#%2$06X</tt> and an estimated background color of <tt>#%3$06X</tt>. Consider increasing this item\'s text contrast ratio to the configured ratio of %4$.2f or greater.
+result_message_textview_heuristic_customized_contrast_not_sufficient_confirmed = The item\'s text contrast ratio is %1$.2f. This ratio is based on the provided foreground color of <tt>#%2$06X</tt> and provided background color of <tt>#%3$06X</tt>. Consider increasing this item\'s text contrast ratio to the configured ratio of %4$.2f or greater.
+result_message_traversal_cycle = This item may be part of a traversal ordering cycle due to its <tt>%1$s</tt> attribute.  Traversal behavior with screen readers may be unpredictable.
+result_message_traversal_over_constrained = Traversal ordering for this item may be over constrained based on its <tt>android:accessibilityTraversalBefore</tt> and <tt>android:accessibilityTraversalAfter</tt> attributes. Traversal behavior with screen readers may be unpredictable.
+result_message_urlspan_invalid_url = Verify that the URL within this item\'s <tt>URLSpan</tt> is valid.
+result_message_urlspan_not_clickablespan = This item should use a <tt>URLSpan</tt> in place of a <tt>ClickableSpan</tt>.
+result_message_view_bounds = This %1$s item also has an on-screen location of <tt>%2$s</tt>.
+result_message_view_not_within_screencapture = This item\'s on-screen location (<tt>%1$s</tt>) were not within the screen capture on-screen location (<tt>%2$s</tt>).
+result_message_web_content = Web content is not evaluated.
+underline_text = underline
diff --git a/validator/src/android/os/Build.java b/validator/src/android/os/Build.java
new file mode 100644
index 0000000..971f466
--- /dev/null
+++ b/validator/src/android/os/Build.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+public class Build {
+    public static class VERSION {
+        public static int SDK_INT = _Original_Build.VERSION.SDK_INT;
+    }
+
+    public static class VERSION_CODES {
+        public final static int Q = _Original_Build.VERSION_CODES.Q;
+        public final static int N = _Original_Build.VERSION_CODES.N;
+        public final static int LOLLIPOP_MR1 = _Original_Build.VERSION_CODES.LOLLIPOP_MR1;
+        public final static int LOLLIPOP = _Original_Build.VERSION_CODES.LOLLIPOP;
+
+        public final static int JELLY_BEAN = _Original_Build.VERSION_CODES.JELLY_BEAN;
+        public final static int HONEYCOMB = _Original_Build.VERSION_CODES.HONEYCOMB;
+        public final static int JELLY_BEAN_MR2 = _Original_Build.VERSION_CODES.JELLY_BEAN_MR2;
+        public final static int JELLY_BEAN_MR1 = _Original_Build.VERSION_CODES.JELLY_BEAN_MR1;
+    }
+}
diff --git a/validator/src/com/android/tools/idea/validator/LayoutValidator.java b/validator/src/com/android/tools/idea/validator/LayoutValidator.java
new file mode 100644
index 0000000..0312ca9
--- /dev/null
+++ b/validator/src/com/android/tools/idea/validator/LayoutValidator.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tools.idea.validator;
+
+import com.android.tools.idea.validator.ValidatorData.Level;
+import com.android.tools.idea.validator.ValidatorData.Policy;
+import com.android.tools.idea.validator.ValidatorData.Type;
+import com.android.tools.idea.validator.accessibility.AccessibilityValidator;
+import com.android.tools.layoutlib.annotations.NotNull;
+
+import android.view.View;
+
+import java.util.EnumSet;
+
+/**
+ * Main class for validating layout.
+ */
+public class LayoutValidator {
+
+    private static final ValidatorData.Policy DEFAULT_POLICY = new Policy(
+            EnumSet.of(Type.ACCESSIBILITY, Type.RENDER),
+            EnumSet.of(Level.ERROR, Level.WARNING));
+
+    /**
+     * Validate the layout using the default policy.
+     * Precondition: View must be attached to the window.
+     *
+     * @return The validation results. If no issue is found it'll return empty result.
+     */
+    @NotNull
+    public static ValidatorResult validate(@NotNull View view) {
+        if (view.isAttachedToWindow()) {
+            return AccessibilityValidator.validateAccessibility(view, DEFAULT_POLICY.mLevels);
+        }
+        // TODO: Add non-a11y layout validation later.
+        return new ValidatorResult.Builder().build();
+    }
+}
diff --git a/validator/src/com/android/tools/idea/validator/ValidatorData.java b/validator/src/com/android/tools/idea/validator/ValidatorData.java
new file mode 100644
index 0000000..f2112a5
--- /dev/null
+++ b/validator/src/com/android/tools/idea/validator/ValidatorData.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tools.idea.validator;
+
+import com.android.tools.layoutlib.annotations.NotNull;
+import com.android.tools.layoutlib.annotations.Nullable;
+
+import java.util.EnumSet;
+
+/**
+ * Data used for layout validation.
+ */
+public class ValidatorData {
+
+    /**
+     * Category of validation
+     */
+    public enum Type {
+        ACCESSIBILITY,
+        RENDER,
+    }
+
+    /**
+     * Level of importance
+     */
+    public enum Level {
+        ERROR,
+        WARNING,
+        INFO,
+        VERBOSE
+    }
+
+    /**
+     * Determine what types and levels of validation to run.
+     */
+    public static class Policy {
+        @NotNull final EnumSet<Type> mTypes;
+        @NotNull final EnumSet<Level> mLevels;
+
+        public Policy(@NotNull EnumSet<Type> types, @NotNull EnumSet<Level> levels) {
+            mTypes = types;
+            mLevels = levels;
+        }
+    }
+
+    /**
+     * Suggested fix to the user or to the studio.
+     */
+    public static class Fix {
+        @NotNull public final String mFix;
+
+        public Fix(String fix) {
+            mFix = fix;
+        }
+    }
+
+    /**
+     * Issue describing the layout problem.
+     */
+    public static class Issue{
+        @NotNull public final Type mType;
+        @NotNull public final String mMsg;
+        @NotNull public final Level mLevel;
+        @Nullable public final Long mSrcId;
+        @Nullable public final Fix mFix;
+
+        public Issue(
+                @NotNull Type type,
+                @NotNull String msg,
+                @NotNull Level level,
+                @Nullable Long srcId,
+                @Nullable Fix fix) {
+            mType = type;
+            mMsg = msg;
+            mLevel = level;
+            mSrcId = srcId;
+            mFix = fix;
+        }
+    }
+}
diff --git a/validator/src/com/android/tools/idea/validator/ValidatorResult.java b/validator/src/com/android/tools/idea/validator/ValidatorResult.java
new file mode 100644
index 0000000..79129bc
--- /dev/null
+++ b/validator/src/com/android/tools/idea/validator/ValidatorResult.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tools.idea.validator;
+
+import com.android.tools.idea.validator.ValidatorData.Issue;
+import com.android.tools.idea.validator.ValidatorData.Level;
+import com.android.tools.layoutlib.annotations.NotNull;
+
+import android.view.View;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+import com.google.common.collect.ImmutableBiMap;
+
+/**
+ * Results of layout validation.
+ */
+public class ValidatorResult {
+
+    @NotNull private final ImmutableBiMap<Long, View> mSrcMap;
+    @NotNull private final ArrayList<Issue> mIssues;
+
+    /**
+     * Please use {@link Builder} for creating results.
+     */
+    private ValidatorResult(BiMap<Long, View> srcMap, ArrayList<Issue> issues) {
+        mSrcMap = ImmutableBiMap.<Long, View>builder().putAll(srcMap).build();
+        mIssues = issues;
+    }
+
+    /**
+     * @return the source map of all the Views.
+     */
+    public ImmutableBiMap<Long, View> getSrcMap() {
+        return mSrcMap;
+    }
+
+    /**
+     * @return list of issues.
+     */
+    public List<Issue> getIssues() {
+        return mIssues;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder builder = new StringBuilder()
+                .append("Result containing ")
+                .append(mIssues.size())
+                .append(" issues:\n");
+
+        for (Issue issue : mIssues) {
+            if (issue.mLevel == Level.ERROR) {
+                builder.append(" - [")
+                        .append(issue.mLevel.name())
+                        .append("] ")
+                        .append(issue.mMsg)
+                        .append("\n");
+            }
+        }
+        return builder.toString();
+    }
+
+    public static class Builder {
+        @NotNull public final BiMap<Long, View> mSrcMap = HashBiMap.create();
+        @NotNull public final ArrayList<Issue> mIssues = new ArrayList<>();
+
+        public ValidatorResult build() {
+            return new ValidatorResult(mSrcMap, mIssues);
+        }
+
+    }
+}
diff --git a/validator/src/com/android/tools/idea/validator/accessibility/AccessibilityValidator.java b/validator/src/com/android/tools/idea/validator/accessibility/AccessibilityValidator.java
new file mode 100644
index 0000000..3f59ff9
--- /dev/null
+++ b/validator/src/com/android/tools/idea/validator/accessibility/AccessibilityValidator.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tools.idea.validator.accessibility;
+
+import com.android.tools.idea.validator.ValidatorData;
+import com.android.tools.idea.validator.ValidatorData.Fix;
+import com.android.tools.idea.validator.ValidatorData.Issue;
+import com.android.tools.idea.validator.ValidatorData.Level;
+import com.android.tools.idea.validator.ValidatorData.Type;
+import com.android.tools.idea.validator.ValidatorResult;
+import com.android.tools.layoutlib.annotations.NotNull;
+import com.android.tools.layoutlib.annotations.Nullable;
+
+import android.view.View;
+
+import java.util.ArrayList;
+import java.util.EnumSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.ResourceBundle;
+import java.util.Set;
+
+import com.google.android.apps.common.testing.accessibility.framework.AccessibilityCheckPreset;
+import com.google.android.apps.common.testing.accessibility.framework.AccessibilityCheckResult.AccessibilityCheckResultType;
+import com.google.android.apps.common.testing.accessibility.framework.AccessibilityHierarchyCheck;
+import com.google.android.apps.common.testing.accessibility.framework.AccessibilityHierarchyCheckResult;
+import com.google.android.apps.common.testing.accessibility.framework.strings.StringManager;
+import com.google.android.apps.common.testing.accessibility.framework.uielement.AccessibilityHierarchyAndroid;
+import com.google.common.collect.BiMap;
+
+/**
+ * Validator specific for running Accessibility specific issues.
+ */
+public class AccessibilityValidator {
+
+    static {
+        /**
+         * Overriding default ResourceBundle ATF uses. ATF would use generic Java resources
+         * instead of Android's .xml.
+         *
+         * By default ATF generates ResourceBundle to support Android specific env/ classloader,
+         * which is quite different from Layoutlib, which supports multiple classloader depending
+         * on env (testing vs in studio).
+         *
+         * To support ATF in Layoutlib, easiest way is to convert resources from Android xml to
+         * generic Java resources (strings.properties), and have the default ResourceBundle ATF
+         * uses be redirected.
+         */
+        StringManager.setResourceBundleProvider(locale -> ResourceBundle.getBundle("strings"));
+    }
+
+    /**
+     * Run Accessibility specific validation test and receive results.
+     * @param view the root view
+     * @param filter list of levels to allow
+     * @return results with all the accessibility issues and warnings.
+     */
+    @NotNull
+    public static ValidatorResult validateAccessibility(
+            @NotNull View view,
+            @NotNull EnumSet<Level> filter) {
+        ValidatorResult.Builder builder = new ValidatorResult.Builder();
+
+        List<AccessibilityHierarchyCheckResult> results = getHierarchyCheckResults(view,
+                builder.mSrcMap);
+
+        for (AccessibilityHierarchyCheckResult result : results) {
+            ValidatorData.Level level = convertLevel(result.getType());
+            if (!filter.contains(level)) {
+                continue;
+            }
+
+            ValidatorData.Fix fix = generateFix(result);
+            Long srcId = null;
+            if (result.getElement() != null) {
+                srcId = result.getElement().getCondensedUniqueId();
+            }
+            Issue issue = new Issue(
+                    Type.ACCESSIBILITY,
+                    result.getMessage(Locale.ENGLISH).toString(),
+                    level,
+                    srcId,
+                    fix);
+            builder.mIssues.add(issue);
+        }
+        return builder.build();
+    }
+
+    @NotNull
+    private static ValidatorData.Level convertLevel(@NotNull AccessibilityCheckResultType type) {
+        switch (type) {
+            case ERROR:
+                return Level.ERROR;
+            case WARNING:
+                return Level.WARNING;
+            case INFO:
+                return Level.INFO;
+            // TODO: Maybe useful later?
+            case SUPPRESSED:
+            case NOT_RUN:
+            default:
+                return Level.VERBOSE;
+        }
+    }
+
+    @Nullable
+    private static ValidatorData.Fix generateFix(@NotNull AccessibilityHierarchyCheckResult result) {
+        // TODO: Once ATF is ready to return us with appropriate fix, build proper fix here.
+        return new Fix("");
+    }
+
+    @NotNull
+    private static List<AccessibilityHierarchyCheckResult> getHierarchyCheckResults(
+            @NotNull View view,
+            @NotNull BiMap<Long, View> originMap) {
+        @NotNull Set<AccessibilityHierarchyCheck> checks = AccessibilityCheckPreset.getAccessibilityHierarchyChecksForPreset(
+                AccessibilityCheckPreset.LATEST);
+        @NotNull AccessibilityHierarchyAndroid hierarchy = AccessibilityHierarchyAndroid.newBuilder(view).setViewOriginMap(originMap).build();
+        ArrayList<AccessibilityHierarchyCheckResult> a11yResults = new ArrayList();
+
+        for (AccessibilityHierarchyCheck check : checks) {
+            a11yResults.addAll(check.runCheckOnHierarchy(hierarchy));
+        }
+
+        return a11yResults;
+    }
+}
diff --git a/validator/validator.iml b/validator/validator.iml
new file mode 100644
index 0000000..e75d99a
--- /dev/null
+++ b/validator/validator.iml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
+      <sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+    <orderEntry type="library" name="framework.jar" level="project" />
+    <orderEntry type="module-library">
+      <library name="guava">
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/m2/repository/com/google/guava/guava/22.0/guava-22.0.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/m2/repository/com/google/guava/guava/22.0/guava-22.0-sources.jar!/" />
+        </SOURCES>
+      </library>
+    </orderEntry>
+    <orderEntry type="module" module-name="common" />
+    <orderEntry type="library" name="framework.jar" level="project" />
+    <orderEntry type="library" scope="TEST" name="hamcrest" level="project" />
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/m2/repository/com/google/protobuf/protobuf-lite/3.0.1/protobuf-lite-3.0.1.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/tools/common/m2/repository/org/jsoup/jsoup/1.6.3/jsoup-1.6.3.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+    <orderEntry type="module-library">
+      <library>
+        <CLASSES>
+          <root url="jar://$MODULE_DIR$/../../../prebuilts/misc/common/atf/atf_classes.jar!/" />
+        </CLASSES>
+        <JAVADOC />
+        <SOURCES />
+      </library>
+    </orderEntry>
+  </component>
+</module>
\ No newline at end of file