Merge 923597a629e236a9b49f1e986edd990a224a4839 on remote branch

Change-Id: Ie6f9eeecb08c08cd1a2a755f9618e2c89dfa11ef
diff --git a/Android.bp b/Android.bp
index acdbffd..b38baa2 100644
--- a/Android.bp
+++ b/Android.bp
@@ -25,6 +25,7 @@
     tools: ["layoutlib_create"],
     out: ["temp_layoutlib.jar"],
     srcs: [
+        ":atf-prebuilt{.jar}",
         ":core-icu4j{.jar}",
         ":core-libart{.jar}",
         ":framework-all{.jar}",
diff --git a/bridge/Android.bp b/bridge/Android.bp
index bca63bc..fa07cb8 100644
--- a/bridge/Android.bp
+++ b/bridge/Android.bp
@@ -31,6 +31,7 @@
         "temp_layoutlib",
         "ninepatch-prebuilt",
         "layoutlib-common",
+        "layoutlib-validator",
     ],
 
     dist: {
@@ -56,6 +57,7 @@
         "tools-common-prebuilt",
         "ninepatch-prebuilt",
         "layoutlib-common",
+        "layoutlib-validator",
     ],
 
     dist: {
diff --git a/bridge/bridge.iml b/bridge/bridge.iml
index 2e782e2..9358a54 100644
--- a/bridge/bridge.iml
+++ b/bridge/bridge.iml
@@ -92,5 +92,15 @@
         </SOURCES>
       </library>
     </orderEntry>
+    <orderEntry type="module" module-name="validator" />
+    <orderEntry type="module-library" scope="TEST">
+      <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
diff --git a/bridge/src/android/content/res/Resources_Delegate.java b/bridge/src/android/content/res/Resources_Delegate.java
index cd57d5c..a5216bc 100644
--- a/bridge/src/android/content/res/Resources_Delegate.java
+++ b/bridge/src/android/content/res/Resources_Delegate.java
@@ -51,7 +51,6 @@
 import android.annotation.Nullable;
 import android.content.res.Resources.NotFoundException;
 import android.content.res.Resources.Theme;
-import android.graphics.Color;
 import android.graphics.Typeface;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.DrawableInflater_Delegate;
@@ -368,7 +367,7 @@
                     try {
                         if (element.startsWith("#")) {
                             // This integer represents a color (starts with #).
-                            values[i] = Color.parseColor(element);
+                            values[i] = ResourceHelper.getColor(element);
                         } else {
                             values[i] = getInt(element);
                         }
diff --git a/bridge/src/android/graphics/Typeface_Delegate.java b/bridge/src/android/graphics/Typeface_Delegate.java
index 35146f4..fb044d9 100644
--- a/bridge/src/android/graphics/Typeface_Delegate.java
+++ b/bridge/src/android/graphics/Typeface_Delegate.java
@@ -257,7 +257,7 @@
             }
 
             if (parser != null) {
-                // TODO(namespaces): The aapt namespace should not matter for parsing font files?
+                // TODO(b/156609434): The aapt namespace should not matter for parsing font files?
                 BridgeXmlBlockParser blockParser =
                         new BridgeXmlBlockParser(
                                 parser, context, ResourceNamespace.fromBoolean(isFramework));
diff --git a/bridge/src/android/util/BridgeXmlPullAttributes.java b/bridge/src/android/util/BridgeXmlPullAttributes.java
index 2f4b0ca..8a78fa3 100644
--- a/bridge/src/android/util/BridgeXmlPullAttributes.java
+++ b/bridge/src/android/util/BridgeXmlPullAttributes.java
@@ -104,15 +104,11 @@
             return Bridge.getResourceId(ResourceType.ATTR, name);
         }
 
-        // this is not an attribute in the android namespace, we query the customviewloader, if
-        // the namespaces match.
-        if (mContext.getLayoutlibCallback().getNamespace().equals(ns)) {
-            // TODO(namespaces): cache the namespace objects.
-            ResourceNamespace namespace = ResourceNamespace.fromNamespaceUri(ns);
-            if (namespace != null) {
-                return mContext.getLayoutlibCallback().getOrGenerateResourceId(
-                        ResourceReference.attr(namespace, name));
-            }
+        // TODO(b/156609434): cache the namespace objects.
+        ResourceNamespace namespace = ResourceNamespace.fromNamespaceUri(ns);
+        if (namespace != null) {
+            return mContext.getLayoutlibCallback().getOrGenerateResourceId(
+                    ResourceReference.attr(namespace, name));
         }
 
         return 0;
diff --git a/bridge/src/com/android/layoutlib/bridge/Bridge.java b/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 0121e92..88298d6 100644
--- a/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -532,7 +532,7 @@
     /**
      * Returns details of a framework resource from its integer value.
      *
-     * <p>TODO(namespaces): remove this and just do all id resolution through the callback.
+     * <p>TODO(b/156609434): remove this and just do all id resolution through the callback.
      */
     @Nullable
     public static ResourceReference resolveResourceId(int value) {
diff --git a/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java b/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
index d61e933..442a77b 100644
--- a/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
+++ b/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
@@ -154,4 +154,12 @@
         }
         mLastResult = lastResult;
     }
+
+    @Override
+    public Object getValidationData() {
+        if (mSession != null) {
+            return mSession.getValidatorResult();
+        }
+        return null;
+    }
 }
diff --git a/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index d1d37fd..e1e6150 100644
--- a/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -32,6 +32,7 @@
 import com.android.layoutlib.bridge.BridgeConstants;
 import com.android.layoutlib.bridge.android.view.WindowManagerImpl;
 import com.android.layoutlib.bridge.impl.ParserFactory;
+import com.android.layoutlib.bridge.impl.ResourceHelper;
 import com.android.layoutlib.bridge.impl.Stack;
 import com.android.resources.ResourceType;
 import com.android.util.Pair;
@@ -66,7 +67,6 @@
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteDatabase.CursorFactory;
 import android.graphics.Bitmap;
-import android.graphics.Color;
 import android.graphics.drawable.Drawable;
 import android.hardware.display.DisplayManager;
 import android.net.Uri;
@@ -416,8 +416,20 @@
         String stringValue = value.getValue();
         if (!stringValue.isEmpty()) {
             if (stringValue.charAt(0) == '#') {
-                outValue.type = TypedValue.TYPE_INT_COLOR_ARGB8;
-                outValue.data = Color.parseColor(value.getValue());
+                outValue.data = ResourceHelper.getColor(stringValue);
+                switch (stringValue.length()) {
+                    case 4:
+                        outValue.type = TypedValue.TYPE_INT_COLOR_RGB4;
+                        break;
+                    case 5:
+                        outValue.type = TypedValue.TYPE_INT_COLOR_ARGB4;
+                        break;
+                    case 7:
+                        outValue.type = TypedValue.TYPE_INT_COLOR_RGB8;
+                        break;
+                    default:
+                        outValue.type = TypedValue.TYPE_INT_COLOR_ARGB8;
+                }
             }
             else if (stringValue.charAt(0) == '@') {
                 outValue.type = TypedValue.TYPE_REFERENCE;
@@ -1084,7 +1096,7 @@
      * Maps a given style to a numeric id.
      *
      * <p>For now Bridge handles numeric ids (both fixed and dynamic) for framework and the callback
-     * for non-framework. TODO(namespaces): teach the IDE about fixed framework ids and handle this
+     * for non-framework. TODO(b/156609434): teach the IDE about fixed framework ids and handle this
      * all in the callback.
      */
     public int getDynamicIdByStyle(StyleResourceValue resValue) {
@@ -1099,7 +1111,7 @@
      * Maps a numeric id back to {@link StyleResourceValue}.
      *
      * <p>For now framework numeric ids are handled by Bridge, so try there first and fall back to
-     * the callback, which manages ids for non-framework resources. TODO(namespaces): manage all
+     * the callback, which manages ids for non-framework resources. TODO(b/156609434): manage all
      * ids in the IDE.
      *
      * <p>Once we the resource for the given id, we ask the IDE to get the
diff --git a/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java b/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java
index a2f5976..4eaf352 100644
--- a/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java
+++ b/bridge/src/com/android/layoutlib/bridge/android/RenderParamsFlags.java
@@ -87,6 +87,19 @@
     public static final Key<Boolean> FLAG_ENABLE_SHADOW =
             new Key<>("enableShadow", Boolean.class);
 
+    /**
+     * Enables layout validation calls within rendering.
+     */
+    public static final Key<Boolean> FLAG_ENABLE_LAYOUT_VALIDATOR =
+            new Key<>("enableLayoutValidator", Boolean.class);
+
+    /**
+     * Enables image-related validation checks within layout validation.
+     * {@link FLAG_ENABLE_LAYOUT_VALIDATOR} must be enabled before this can be effective.
+     */
+    public static final Key<Boolean> FLAG_ENABLE_LAYOUT_VALIDATOR_IMAGE_CHECK =
+            new Key<>("enableLayoutValidatorImageCheck", Boolean.class);
+
     // Disallow instances.
     private RenderParamsFlags() {}
 }
diff --git a/bridge/src/com/android/layoutlib/bridge/android/view/WindowManagerImpl.java b/bridge/src/com/android/layoutlib/bridge/android/view/WindowManagerImpl.java
index ae4c929..318c0f4 100644
--- a/bridge/src/com/android/layoutlib/bridge/android/view/WindowManagerImpl.java
+++ b/bridge/src/com/android/layoutlib/bridge/android/view/WindowManagerImpl.java
@@ -52,6 +52,7 @@
         info.supportedModes = new Mode[] {
                 new Mode(0, mMetrics.widthPixels, mMetrics.heightPixels, 60f)
         };
+        info.logicalDensityDpi = mMetrics.densityDpi;
         mDisplay = new Display(null, Display.DEFAULT_DISPLAY, info,
                 DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS);
     }
diff --git a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index e7904ab..1338c17 100644
--- a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -47,6 +47,10 @@
 import com.android.layoutlib.bridge.impl.binding.FakeAdapter;
 import com.android.layoutlib.bridge.impl.binding.FakeExpandableAdapter;
 import com.android.tools.layoutlib.java.System_Delegate;
+import com.android.tools.idea.validator.ValidatorResult;
+import com.android.tools.idea.validator.LayoutValidator;
+import com.android.tools.idea.validator.ValidatorResult;
+import com.android.tools.idea.validator.ValidatorResult.Builder;
 import com.android.util.Pair;
 
 import android.annotation.NonNull;
@@ -127,6 +131,7 @@
     private List<ViewInfo> mSystemViewInfoList;
     private Layout.Builder mLayoutBuilder;
     private boolean mNewRenderSize;
+    @Nullable private ValidatorResult mValidatorResult = null;
 
     private static final class PostInflateException extends Exception {
         private static final long serialVersionUID = 1L;
@@ -569,6 +574,24 @@
                     visitAllChildren(mViewRoot, 0, 0, params.getExtendedViewInfoMode(),
                     false);
 
+            try {
+                boolean enableLayoutValidation = Boolean.TRUE.equals(params.getFlag(RenderParamsFlags.FLAG_ENABLE_LAYOUT_VALIDATOR));
+                boolean enableLayoutValidationImageCheck = Boolean.TRUE.equals(
+                         params.getFlag(RenderParamsFlags.FLAG_ENABLE_LAYOUT_VALIDATOR_IMAGE_CHECK));
+
+                if (enableLayoutValidation && !getViewInfos().isEmpty()) {
+                    BufferedImage imageToPass =
+                            enableLayoutValidationImageCheck ? getImage() : null;
+                    ValidatorResult validatorResult =
+                            LayoutValidator.validate(((View) getViewInfos().get(0).getViewObject()), imageToPass);
+                    setValidatorResult(validatorResult);
+                }
+            } catch (Throwable e) {
+                ValidatorResult.Builder builder = new Builder();
+                builder.mMetric.mErrorMessage = e.getMessage();
+                setValidatorResult(builder.build());
+            }
+
             // success!
             return renderResult;
         } catch (Throwable e) {
@@ -1130,6 +1153,15 @@
         return getContext().getDefaultNamespacedStyles();
     }
 
+    @Nullable
+    public ValidatorResult getValidatorResult() {
+        return mValidatorResult;
+    }
+
+    public void setValidatorResult(ValidatorResult result) {
+        mValidatorResult = result;
+    }
+
     public void setScene(RenderSession session) {
         mScene = session;
     }
diff --git a/bridge/src/com/android/layoutlib/bridge/resources/SysUiResources.java b/bridge/src/com/android/layoutlib/bridge/resources/SysUiResources.java
index 96a6e34..d84b411 100644
--- a/bridge/src/com/android/layoutlib/bridge/resources/SysUiResources.java
+++ b/bridge/src/com/android/layoutlib/bridge/resources/SysUiResources.java
@@ -52,7 +52,7 @@
                 try {
                     XmlPullParser parser = ParserFactory.create(stream, layoutName);
 
-                    // TODO(namespaces): does the namespace matter here?
+                    // TODO(b/156609434): does the namespace matter here?
                     return new BridgeXmlBlockParser(parser, context, PRIVATE_LAYOUTLIB_NAMESPACE);
                 } catch (XmlPullParserException e) {
                     // Should not happen as the resource is bundled with the jar, and  ParserFactory should
diff --git a/bridge/tests/res/testApp/MyApplication/golden/a11y_test1.png b/bridge/tests/res/testApp/MyApplication/golden/a11y_test1.png
new file mode 100644
index 0000000..067a193
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/golden/a11y_test1.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/eye_chart.png b/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/eye_chart.png
new file mode 100644
index 0000000..d195080
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/eye_chart.png
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/eye_chart_low_contrast.jpg b/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/eye_chart_low_contrast.jpg
new file mode 100644
index 0000000..f578c26
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/src/main/res/drawable/eye_chart_low_contrast.jpg
Binary files differ
diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test1.xml b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test1.xml
new file mode 100644
index 0000000..3af420c
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test1.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <android.widget.TextView
+        android:layout_width="100dp"
+        android:layout_height="100dp"
+        android:background="#000000"
+        android:gravity="center"
+        android:text="Hello!"
+        android:textColor="#000000" />
+
+
+    <Button
+        android:layout_width="10dp"
+        android:layout_height="10dp"
+        android:text="Hello World!!!"
+    />
+    <View
+        android:layout_width="100dp"
+        android:layout_height="100dp"
+        android:background="#000000"
+        android:importantForAccessibility="yes"
+        android:focusable="true"
+        android:clickable="true"
+    />
+</LinearLayout>
diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test_dup_clickable_bounds.xml b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test_dup_clickable_bounds.xml
new file mode 100644
index 0000000..cbc04ac
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test_dup_clickable_bounds.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+
+<!-- Accessibility test with decoy clickable item -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical">
+
+    <LinearLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:id="@+id/clickable_wrapper_for_button"
+        android:orientation="horizontal"
+        android:clickable="true">
+
+        <Button
+            android:text="Button in clickable parent"
+            android:id="@+id/button_in_clickable_parent"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:minHeight="48dp"/>
+    </LinearLayout>
+
+    <Button
+        android:text="Button on its own"
+        android:id="@+id/button_on_its_own"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:minHeight="48dp"/>
+
+</LinearLayout>
diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test_duplicate_speakable.xml b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test_duplicate_speakable.xml
new file mode 100644
index 0000000..676a2d4
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test_duplicate_speakable.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/layout_across_top"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:orientation="vertical">
+    <TextView
+        android:id="@+id/first_news_text"
+        android:text="News"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:padding="16dp"
+        android:textSize="32dp"/>
+    <Button
+        android:id="@+id/first_print_button"
+        android:text="Print"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"/>
+
+    <TextView
+        android:id="@+id/first_news_text1"
+        android:text="News"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:padding="16dp"
+        android:textSize="32dp"/>
+    <Button
+        android:id="@+id/first_print_button2"
+        android:text="Print"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"/>
+</LinearLayout>
diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test_image_contrast.xml b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test_image_contrast.xml
new file mode 100644
index 0000000..0f20c19
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test_image_contrast.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:gravity="top|center_horizontal"
+              android:orientation="vertical">
+
+    <ImageView
+        android:layout_width="97dp"
+        android:layout_height="wrap_content"
+        android:layout_margin="8dp"
+        android:adjustViewBounds="true"
+        android:src="@drawable/eye_chart"
+        android:contentDescription="Eye Chart"
+        android:clickable="true" />
+
+    <ImageView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_margin="8dp"
+        android:layout_marginTop="0dp"
+        android:src="@drawable/eye_chart_low_contrast"
+        android:contentDescription="Eye Chart with Low Contrast"
+        android:clickable="true" />
+</LinearLayout>
\ No newline at end of file
diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test_redundant_desc.xml b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test_redundant_desc.xml
new file mode 100644
index 0000000..ff99a35
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test_redundant_desc.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical">
+
+            <Button
+                android:id="@+id/button_with_label_containing_button"
+                android:text="OK"
+                android:contentDescription="OK button"
+                android:layout_width="wrap_content"
+                android:layout_height="48dp" />
+
+            <TextView
+                android:id="@+id/oath"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:padding="16dp"
+                android:text="I hereby declare, on oath, that I absolutely and entirely renounce and abjure all allegiance
+    and fidelity to any foreign prince, potentate, state, or sovereignty of whom or which I have
+    heretofore been a subject or citizen; that I will support and defend the Constitution and
+    laws of the United States of America against all enemies, foreign and domestic; that I will
+    bear true faith and allegiance to the same; that I will bear arms on behalf of the United
+    States when required by the law; that I will perform noncombatant service in the
+    Armed Forces of the United States when required by the law; that I will perform work of
+    national importance under civilian direction when required by the law; and that I take this
+    obligation freely without any mental reservation or purpose of evasion; so help me God."/>
+
+            <Button
+                android:text="Good Button"
+                android:id="@+id/bottom_button"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_margin="8dp" />
+
+</LinearLayout>
diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test_speakable_text_present.xml b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test_speakable_text_present.xml
new file mode 100644
index 0000000..64c2873
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test_speakable_text_present.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+
+<!-- Accessibility test with label -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical">
+
+    <Button
+        android:id="@+id/button_labeled_by_textview"
+        android:layout_width="48dp"
+        android:layout_height="48dp" />
+
+    <TextView
+        android:id="@+id/textview_label"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:labelFor="@id/button_labeled_by_textview"
+        android:minHeight="48dp"
+        android:text="Howdy"/>
+
+</LinearLayout>
diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test_speakable_text_present2.xml b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test_speakable_text_present2.xml
new file mode 100644
index 0000000..c261979
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test_speakable_text_present2.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+
+<!-- Accessibility test with nothing important error msg -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical">
+
+    <Button
+        android:id="@+id/unlabeled_button"
+        android:importantForAccessibility="no"
+        android:layout_width="48dp"
+        android:layout_height="48dp" />
+
+</LinearLayout>
diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test_speakable_text_present3.xml b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test_speakable_text_present3.xml
new file mode 100644
index 0000000..6f9741b
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test_speakable_text_present3.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+
+<!-- Accessibility test with nothing important error msg -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:orientation="vertical">
+
+    <Button
+        android:id="@+id/unlabeled_button2"
+        android:layout_width="48dp"
+        android:layout_height="48dp" />
+
+</LinearLayout>
diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test_text_contrast.xml b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test_text_contrast.xml
new file mode 100644
index 0000000..4d3ac6f
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test_text_contrast.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent"
+              android:gravity="top|center_horizontal"
+              android:orientation="vertical">
+    <!-- Low contrast, with slightly transparent text -->
+    <Button
+        android:id="@+id/low_contrast_button1"
+        android:text="Bad Button"
+        android:layout_width="wrap_content"
+        android:layout_height="48dp"
+        android:layout_margin="8dp"
+        android:layout_marginLeft="0dp"
+        android:background="@android:color/holo_green_dark"
+        android:textColor="#fe0099cc" />
+    <!-- ATF bypasses transparent views / colors unless image is available. -->
+    <Button
+        android:id="@+id/low_contrast_button2"
+        android:layout_width="wrap_content"
+        android:layout_height="48dp"
+        android:background="@android:color/holo_green_dark"
+        android:text="Button B"
+        android:textColor="@android:color/holo_blue_dark"/>
+    <EditText
+        android:id="@+id/low_contrast_edit_text"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:ems="10"
+        android:inputType="textPersonName"
+        android:minHeight="48dp"
+        android:text="Edit B"
+        android:background="@android:color/holo_green_dark"
+        android:textColor="@android:color/holo_blue_dark"
+    />
+    <CheckBox
+        android:id="@+id/low_contrast_check_box"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:background="@android:color/holo_green_dark"
+        android:minHeight="48dp"
+        android:text="CheckBox B"
+        android:textColor="@android:color/holo_blue_dark"/>
+</LinearLayout>
diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test_touch_target_size.xml b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test_touch_target_size.xml
new file mode 100644
index 0000000..58885ac
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test_touch_target_size.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+
+    <Button
+        android:id="@+id/ok_top_left_corner_button1"
+        android:text="E"
+        android:layout_width="32dp"
+        android:layout_height="32dp"
+    />
+
+    <Button
+        android:id="@+id/thin_top_button2"
+        android:text="F"
+        android:layout_width="32dp"
+        android:layout_height="48dp"
+        />
+
+    <Button
+        android:id="@+id/ok_top_button3"
+        android:text="G"
+        android:layout_width="48dp"
+        android:layout_height="32dp"
+        />
+
+    <Button
+        android:id="@+id/short_top_button4"
+        android:text="H"
+        android:layout_width="48dp"
+        android:layout_height="31dp"
+        />
+
+    <Button
+        android:id="@+id/short_top_right_corner_button5"
+        android:text="I"
+        android:layout_width="32dp"
+        android:layout_height="31dp"
+        />
+
+</LinearLayout>
diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/values/styles.xml b/bridge/tests/res/testApp/MyApplication/src/main/res/values/styles.xml
index f598fda..9e84a53 100644
--- a/bridge/tests/res/testApp/MyApplication/src/main/res/values/styles.xml
+++ b/bridge/tests/res/testApp/MyApplication/src/main/res/values/styles.xml
@@ -3,6 +3,8 @@
     <!-- Base application theme. -->
     <style name="AppTheme" parent="android:Theme.Material.Light.DarkActionBar">
         <item name="myattr">@integer/ten</item>
+        <item name="android:colorError">#f00</item>
+        <item name="android:colorActivatedHighlight">#c0f0</item>
     </style>
 
     <style name="ThemableWidgetStyle">
diff --git a/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java b/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
index 3db0644..e43531a 100644
--- a/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
+++ b/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
@@ -22,6 +22,8 @@
 import com.android.layoutlib.bridge.android.BridgeXmlBlockParserTest;
 import com.android.layoutlib.bridge.impl.LayoutParserWrapperTest;
 import com.android.layoutlib.bridge.impl.ResourceHelperTest;
+import com.android.tools.idea.validator.LayoutValidatorTests;
+import com.android.tools.idea.validator.accessibility.AccessibilityValidatorTests;
 
 import org.junit.runner.RunWith;
 import org.junit.runners.Suite;
@@ -44,7 +46,8 @@
         Matrix_DelegateTest.class, TestDelegates.class,
         BridgeRenderSessionTest.class, ResourceHelperTest.class, BridgeContextTest.class,
         Resources_DelegateTest.class, Color_DelegateTest.class, ImagePoolHelperTest.class,
-        ImagePoolImplTest.class, HighQualityShadowsRenderTests.class
+        ImagePoolImplTest.class, HighQualityShadowsRenderTests.class,
+        LayoutValidatorTests.class, AccessibilityValidatorTests.class
 })
 public class Main {
 }
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 77c6d1a..a22c3bc 100644
--- a/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTestBase.java
+++ b/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTestBase.java
@@ -89,6 +89,16 @@
  */
 public class RenderTestBase {
 
+    /**
+     * Listener for render process.
+     */
+    public interface RenderSessionListener {
+
+        /**
+         * Called before session is disposed after rendering.
+         */
+        void beforeDisposed(RenderSession session);
+    }
     private static final String PLATFORM_DIR_PROPERTY = "platform.dir";
     private static final String RESOURCE_DIR_PROPERTY = "test_res.dir";
 
@@ -343,6 +353,14 @@
     protected static RenderResult render(com.android.ide.common.rendering.api.Bridge bridge,
             SessionParams params,
             long frameTimeNanos) {
+        return render(bridge, params, frameTimeNanos, null);
+    }
+
+    @NonNull
+    protected static RenderResult render(com.android.ide.common.rendering.api.Bridge bridge,
+            SessionParams params,
+            long frameTimeNanos,
+            @Nullable RenderSessionListener listener) {
         // TODO: Set up action bar handler properly to test menu rendering.
         // Create session params.
         System_Delegate.setBootTimeNanos(TimeUnit.MILLISECONDS.toNanos(871732800000L));
@@ -366,6 +384,9 @@
                             session.getResult().getErrorMessage());
                 }
             }
+            if (listener != null) {
+                listener.beforeDisposed(session);
+            }
 
             return RenderResult.getFromSession(session);
         } finally {
diff --git a/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java b/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java
index 5118426..303c247 100644
--- a/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java
+++ b/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java
@@ -43,6 +43,7 @@
 import org.kxml2.io.KXmlParser;
 import org.xmlpull.v1.XmlPullParser;
 
+import android.R.attr;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.res.AssetManager;
@@ -965,6 +966,16 @@
         assertNotEquals(0, outValue.data);
 
         outValue = new TypedValue();
+        mContext.resolveThemeAttribute(android.R.attr.colorError, outValue, true);
+        assertEquals(TypedValue.TYPE_INT_COLOR_RGB4, outValue.type);
+        assertEquals(-65536, outValue.data);
+
+        outValue = new TypedValue();
+        mContext.resolveThemeAttribute(attr.colorActivatedHighlight, outValue, true);
+        assertEquals(TypedValue.TYPE_INT_COLOR_ARGB4, outValue.type);
+        assertEquals(-872349952, outValue.data);
+
+        outValue = new TypedValue();
         mContext.resolveThemeAttribute(android.R.attr.isLightTheme, outValue, true);
         assertEquals(TypedValue.TYPE_INT_BOOLEAN, outValue.type);
         assertEquals(1, outValue.data);
diff --git a/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java b/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java
index bbe9d3c..a6389ac 100644
--- a/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java
+++ b/bridge/tests/src/com/android/layoutlib/bridge/intensive/setup/LayoutLibTestCallback.java
@@ -108,13 +108,6 @@
         return viewConstructor.newInstance(constructorArgs);
     }
 
-    @NonNull
-    @Override
-    public String getNamespace() {
-        return String.format(SdkConstants.NS_CUSTOM_RESOURCES_S,
-                PACKAGE_NAME);
-    }
-
     @Override
     public ResourceReference resolveResourceId(int id) {
         return mProjectResources.get(id);
diff --git a/bridge/tests/src/com/android/layoutlib/bridge/intensive/util/SessionParamsBuilder.java b/bridge/tests/src/com/android/layoutlib/bridge/intensive/util/SessionParamsBuilder.java
index 6fbb955..baadc62 100644
--- a/bridge/tests/src/com/android/layoutlib/bridge/intensive/util/SessionParamsBuilder.java
+++ b/bridge/tests/src/com/android/layoutlib/bridge/intensive/util/SessionParamsBuilder.java
@@ -63,6 +63,8 @@
     private IImageFactory mImageFactory = null;
     private boolean enableShadows = true;
     private boolean highQualityShadows = true;
+    private boolean enableLayoutValidator = false;
+    private boolean enableLayoutValidatorImageCheck = false;
 
     @NonNull
     public SessionParamsBuilder setParser(@NonNull LayoutPullParser layoutParser) {
@@ -176,6 +178,18 @@
     }
 
     @NonNull
+    public SessionParamsBuilder enableLayoutValidation() {
+        this.enableLayoutValidator = true;
+        return this;
+    }
+
+    @NonNull
+    public SessionParamsBuilder enableLayoutValidationImageCheck() {
+        this.enableLayoutValidatorImageCheck = true;
+        return this;
+    }
+
+    @NonNull
     public SessionParams build() {
         assert mFrameworkResources != null;
         assert mProjectResources != null;
@@ -198,6 +212,10 @@
                 mMinSdk, mTargetSdk, mLayoutLog);
         params.setFlag(RenderParamsFlags.FLAG_ENABLE_SHADOW, enableShadows);
         params.setFlag(RenderParamsFlags.FLAG_RENDER_HIGH_QUALITY_SHADOW, highQualityShadows);
+        params.setFlag(RenderParamsFlags.FLAG_ENABLE_LAYOUT_VALIDATOR, enableLayoutValidator);
+        params.setFlag(
+                RenderParamsFlags.FLAG_ENABLE_LAYOUT_VALIDATOR_IMAGE_CHECK,
+                enableLayoutValidatorImageCheck);
         if (mImageFactory != null) {
             params.setImageFactory(mImageFactory);
         }
diff --git a/bridge/tests/src/com/android/tools/idea/validator/LayoutValidatorTests.java b/bridge/tests/src/com/android/tools/idea/validator/LayoutValidatorTests.java
new file mode 100644
index 0000000..ec91e17
--- /dev/null
+++ b/bridge/tests/src/com/android/tools/idea/validator/LayoutValidatorTests.java
@@ -0,0 +1,182 @@
+/*
+ * 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.ide.common.rendering.api.SessionParams;
+import com.android.layoutlib.bridge.intensive.RenderTestBase;
+import com.android.layoutlib.bridge.intensive.setup.ConfigGenerator;
+import com.android.layoutlib.bridge.intensive.setup.LayoutLibTestCallback;
+import com.android.layoutlib.bridge.intensive.setup.LayoutPullParser;
+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 org.junit.Test;
+
+import android.view.View;
+
+import java.util.EnumSet;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import com.google.android.apps.common.testing.accessibility.framework.AccessibilityCheckPreset;
+import com.google.android.apps.common.testing.accessibility.framework.AccessibilityHierarchyCheck;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class LayoutValidatorTests extends RenderTestBase {
+
+    @Test
+    public void testRenderAndVerify() throws Exception {
+        LayoutPullParser parser = createParserFromPath("a11y_test1.xml");
+        LayoutLibTestCallback layoutLibCallback =
+                new LayoutLibTestCallback(getLogger(), mDefaultClassLoader);
+        layoutLibCallback.initResources();
+        SessionParams params = getSessionParamsBuilder()
+                .setParser(parser)
+                .setConfigGenerator(ConfigGenerator.NEXUS_5)
+                .setCallback(layoutLibCallback)
+                .disableDecoration()
+                .enableLayoutValidation()
+                .build();
+
+        renderAndVerify(params, "a11y_test1.png");
+    }
+
+    @Test
+    public void testValidation() throws Exception {
+        render(sBridge, generateParams(), -1, session -> {
+            ValidatorResult result = LayoutValidator
+                    .validate(((View) session.getRootViews().get(0).getViewObject()), null);
+            assertEquals(3, result.getIssues().size());
+            for (Issue issue : result.getIssues()) {
+                assertEquals(Type.ACCESSIBILITY, issue.mType);
+                assertEquals(Level.ERROR, issue.mLevel);
+            }
+
+            Issue first = result.getIssues().get(0);
+            assertEquals("This item may not have a label readable by screen readers.",
+                         first.mMsg);
+            assertEquals("https://support.google.com/accessibility/android/answer/7158690",
+                         first.mHelpfulUrl);
+            assertEquals("SpeakableTextPresentCheck", first.mSourceClass);
+
+            Issue second = result.getIssues().get(1);
+            assertEquals("This item's size is 10dp x 10dp. Consider making this touch target " +
+                            "48dp wide and 48dp high or larger.",
+                         second.mMsg);
+            assertEquals("https://support.google.com/accessibility/android/answer/7101858",
+                         second.mHelpfulUrl);
+            assertEquals("TouchTargetSizeCheck", second.mSourceClass);
+
+            Issue third = result.getIssues().get(2);
+            assertEquals("The item's text contrast ratio is 1.00. This ratio is based on a text color " +
+                            "of #000000 and background color of #000000. Consider increasing this item's" +
+                            " text contrast ratio to 4.50 or greater.",
+                         third.mMsg);
+            assertEquals("https://support.google.com/accessibility/android/answer/7158390",
+                         third.mHelpfulUrl);
+            assertEquals("TextContrastCheck", third.mSourceClass);
+        });
+    }
+
+    @Test
+    public void testValidationPolicyType() throws Exception {
+        try {
+            ValidatorData.Policy newPolicy = new ValidatorData.Policy(
+                    EnumSet.of(Type.RENDER),
+                    EnumSet.of(Level.ERROR, Level.WARNING));
+            LayoutValidator.updatePolicy(newPolicy);
+
+            render(sBridge, generateParams(), -1, session -> {
+                ValidatorResult result = LayoutValidator.validate(
+                        ((View) session.getRootViews().get(0).getViewObject()), null);
+                assertTrue(result.getIssues().isEmpty());
+            });
+        } finally {
+            LayoutValidator.updatePolicy(LayoutValidator.DEFAULT_POLICY);
+        }
+    }
+
+    @Test
+    public void testValidationPolicyLevel() throws Exception {
+        try {
+            ValidatorData.Policy newPolicy = new ValidatorData.Policy(
+                    EnumSet.of(Type.ACCESSIBILITY, Type.RENDER),
+                    EnumSet.of(Level.VERBOSE));
+            LayoutValidator.updatePolicy(newPolicy);
+
+            render(sBridge, generateParams(), -1, session -> {
+                ValidatorResult result = LayoutValidator.validate(
+                        ((View) session.getRootViews().get(0).getViewObject()), null);
+                assertEquals(27, result.getIssues().size());
+                result.getIssues().forEach(issue ->assertEquals(Level.VERBOSE, issue.mLevel));
+            });
+        } finally {
+            LayoutValidator.updatePolicy(LayoutValidator.DEFAULT_POLICY);
+        }
+    }
+
+    @Test
+    public void testValidationPolicyChecks() throws Exception {
+        Set<AccessibilityHierarchyCheck> allChecks =
+                AccessibilityCheckPreset.getAccessibilityHierarchyChecksForPreset(
+                        AccessibilityCheckPreset.LATEST);
+        Set<AccessibilityHierarchyCheck> filtered =allChecks
+                .stream()
+                .filter(it -> it.getClass().getSimpleName().equals("TextContrastCheck"))
+                .collect(Collectors.toSet());
+        try {
+            ValidatorData.Policy newPolicy = new ValidatorData.Policy(
+                    EnumSet.of(Type.ACCESSIBILITY, Type.RENDER),
+                    EnumSet.of(Level.ERROR));
+            newPolicy.mChecks.addAll(filtered);
+            LayoutValidator.updatePolicy(newPolicy);
+
+            render(sBridge, generateParams(), -1, session -> {
+                ValidatorResult result = LayoutValidator.validate(
+                        ((View) session.getRootViews().get(0).getViewObject()), null);
+                assertEquals(1, result.getIssues().size());
+                Issue textCheck = result.getIssues().get(0);
+                assertEquals("The item's text contrast ratio is 1.00. This ratio is based on a text color " +
+                                "of #000000 and background color of #000000. Consider increasing this item's" +
+                                " text contrast ratio to 4.50 or greater.",
+                        textCheck.mMsg);
+                assertEquals("https://support.google.com/accessibility/android/answer/7158390",
+                        textCheck.mHelpfulUrl);
+                assertEquals("TextContrastCheck", textCheck.mSourceClass);
+            });
+        } finally {
+            LayoutValidator.updatePolicy(LayoutValidator.DEFAULT_POLICY);
+        }
+    }
+
+    private SessionParams generateParams() throws Exception {
+        LayoutPullParser parser = createParserFromPath("a11y_test1.xml");
+        LayoutLibTestCallback layoutLibCallback =
+                new LayoutLibTestCallback(getLogger(), mDefaultClassLoader);
+        layoutLibCallback.initResources();
+        return getSessionParamsBuilder()
+                .setParser(parser)
+                .setConfigGenerator(ConfigGenerator.NEXUS_5)
+                .setCallback(layoutLibCallback)
+                .disableDecoration()
+                .enableLayoutValidation()
+                .build();
+    }
+}
diff --git a/bridge/tests/src/com/android/tools/idea/validator/accessibility/AccessibilityValidatorTests.java b/bridge/tests/src/com/android/tools/idea/validator/accessibility/AccessibilityValidatorTests.java
new file mode 100644
index 0000000..16ad4a2
--- /dev/null
+++ b/bridge/tests/src/com/android/tools/idea/validator/accessibility/AccessibilityValidatorTests.java
@@ -0,0 +1,338 @@
+/*
+ * 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.ide.common.rendering.api.RenderSession;
+import com.android.ide.common.rendering.api.SessionParams;
+import com.android.layoutlib.bridge.intensive.RenderTestBase;
+import com.android.layoutlib.bridge.intensive.setup.ConfigGenerator;
+import com.android.layoutlib.bridge.intensive.setup.LayoutLibTestCallback;
+import com.android.layoutlib.bridge.intensive.setup.LayoutPullParser;
+import com.android.layoutlib.bridge.intensive.util.SessionParamsBuilder;
+import com.android.tools.idea.validator.LayoutValidator;
+import com.android.tools.idea.validator.ValidatorData;
+import com.android.tools.idea.validator.ValidatorData.Issue;
+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.ValidatorResult;
+
+import org.junit.Test;
+
+import java.util.EnumSet;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Sanity check for a11y checks. For now it lacks checking the following:
+ * - ClassNameCheck
+ * - ClickableSpanCheck
+ * - EditableContentDescCheck
+ * - LinkPurposeUnclearCheck
+ * As these require more complex UI for testing.
+ *
+ * It's also missing:
+ * - TraversalOrderCheck
+ * Because in Layoutlib test env, traversalBefore/after attributes seems to be lost. Tested on
+ * studio and it seems to work ok.
+ */
+public class AccessibilityValidatorTests extends RenderTestBase {
+
+    @Test
+    public void testDuplicateClickableBoundsCheck() throws Exception {
+        render("a11y_test_dup_clickable_bounds.xml", session -> {
+            ValidatorResult result = getRenderResult(session);
+            List<Issue> dupBounds = filter(result.getIssues(), "DuplicateClickableBoundsCheck");
+
+            ExpectedLevels expectedLevels = new ExpectedLevels();
+            expectedLevels.expectedErrors = 1;
+            expectedLevels.check(dupBounds);
+        });
+    }
+
+    @Test
+    public void testDuplicateSpeakableTextsCheck() throws Exception {
+        render("a11y_test_duplicate_speakable.xml", session -> {
+            ValidatorResult result = getRenderResult(session);
+            List<Issue> duplicateSpeakableTexts = filter(result.getIssues(),
+                    "DuplicateSpeakableTextCheck");
+
+            ExpectedLevels expectedLevels = new ExpectedLevels();
+            expectedLevels.expectedInfos = 1;
+            expectedLevels.expectedWarnings = 1;
+            expectedLevels.check(duplicateSpeakableTexts);
+        });
+    }
+
+    @Test
+    public void testRedundantDescriptionCheck() throws Exception {
+        render("a11y_test_redundant_desc.xml", session -> {
+            ValidatorResult result = getRenderResult(session);
+            List<Issue> redundant = filter(result.getIssues(), "RedundantDescriptionCheck");
+
+            ExpectedLevels expectedLevels = new ExpectedLevels();
+            expectedLevels.expectedVerboses = 3;
+            expectedLevels.expectedWarnings = 1;
+            expectedLevels.check(redundant);
+        });
+    }
+
+    @Test
+    public void testLabelFor() throws Exception {
+        render("a11y_test_speakable_text_present.xml", session -> {
+            ValidatorResult result = getRenderResult(session);
+            List<Issue> speakableCheck = filter(result.getIssues(), "SpeakableTextPresentCheck");
+
+            // Post-JB MR2 support labelFor, so SpeakableTextPresentCheck does not need to find any
+            // speakable text. Expected 1 verbose result saying something along the line of
+            // didn't run or not important for a11y.
+            ExpectedLevels expectedLevels = new ExpectedLevels();
+            expectedLevels.expectedVerboses = 1;
+            expectedLevels.check(speakableCheck);
+        });
+    }
+
+    @Test
+    public void testImportantForAccessibility() throws Exception {
+        render("a11y_test_speakable_text_present2.xml", session -> {
+            ValidatorResult result = getRenderResult(session);
+            List<Issue> speakableCheck = filter(result.getIssues(), "SpeakableTextPresentCheck");
+
+            // Post-JB MR2 support importantForAccessibility, so SpeakableTextPresentCheck
+            // does not need to find any speakable text. Expected 2 verbose results.
+            ExpectedLevels expectedLevels = new ExpectedLevels();
+            expectedLevels.expectedVerboses = 2;
+            expectedLevels.check(speakableCheck);
+        });
+    }
+
+    @Test
+    public void testSpeakableTextPresentCheck() throws Exception {
+        render("a11y_test_speakable_text_present3.xml", session -> {
+            ValidatorResult result = getRenderResult(session);
+            List<Issue> speakableCheck = filter(result.getIssues(), "SpeakableTextPresentCheck");
+
+            ExpectedLevels expectedLevels = new ExpectedLevels();
+            expectedLevels.expectedVerboses = 1;
+            expectedLevels.expectedErrors = 1;
+            expectedLevels.check(speakableCheck);
+
+            // Make sure no other errors in the system.
+            speakableCheck = filter(speakableCheck, EnumSet.of(Level.ERROR));
+            assertEquals(1, speakableCheck.size());
+            List<Issue> allErrors = filter(
+                    result.getIssues(), EnumSet.of(Level.ERROR, Level.WARNING, Level.INFO));
+            checkEquals(speakableCheck, allErrors);
+        });
+    }
+
+    @Test
+    public void testTextContrastCheck() throws Exception {
+        render("a11y_test_text_contrast.xml", session -> {
+            ValidatorResult result = getRenderResult(session);
+            List<Issue> textContrast = filter(result.getIssues(), "TextContrastCheck");
+
+            // ATF doesn't count alpha values unless image is passed.
+            ExpectedLevels expectedLevels = new ExpectedLevels();
+            expectedLevels.expectedErrors = 3;
+            expectedLevels.expectedWarnings = 1; // This is true only if image is passed.
+            expectedLevels.expectedVerboses = 2;
+            expectedLevels.check(textContrast);
+
+            // Make sure no other errors in the system.
+            textContrast = filter(textContrast, EnumSet.of(Level.ERROR));
+            List<Issue> filtered = filter(result.getIssues(), EnumSet.of(Level.ERROR));
+            checkEquals(filtered, textContrast);
+        });
+    }
+
+    @Test
+    public void testTextContrastCheckNoImage() throws Exception {
+        render("a11y_test_text_contrast.xml", session -> {
+            ValidatorResult result = getRenderResult(session);
+            List<Issue> textContrast = filter(result.getIssues(), "TextContrastCheck");
+
+            // ATF doesn't count alpha values unless image is passed.
+            ExpectedLevels expectedLevels = new ExpectedLevels();
+            expectedLevels.expectedErrors = 3;
+            expectedLevels.expectedVerboses = 3;
+            expectedLevels.check(textContrast);
+
+            // Make sure no other errors in the system.
+            textContrast = filter(textContrast, EnumSet.of(Level.ERROR));
+            List<Issue> filtered = filter(result.getIssues(), EnumSet.of(Level.ERROR));
+            checkEquals(filtered, textContrast);
+        }, false);
+    }
+
+    @Test
+    public void testImageContrastCheck() throws Exception {
+        render("a11y_test_image_contrast.xml", session -> {
+            ValidatorResult result = getRenderResult(session);
+            List<Issue> imageContrast = filter(result.getIssues(), "ImageContrastCheck");
+
+            ExpectedLevels expectedLevels = new ExpectedLevels();
+            expectedLevels.expectedWarnings = 1;
+            expectedLevels.expectedVerboses = 1;
+            expectedLevels.check(imageContrast);
+
+            // Make sure no other errors in the system.
+            imageContrast = filter(imageContrast, EnumSet.of(Level.ERROR, Level.WARNING));
+            List<Issue> filtered = filter(result.getIssues(), EnumSet.of(Level.ERROR, Level.WARNING));
+            checkEquals(filtered, imageContrast);
+        });
+    }
+
+    @Test
+    public void testImageContrastCheckNoImage() throws Exception {
+        render("a11y_test_image_contrast.xml", session -> {
+            ValidatorResult result = getRenderResult(session);
+            List<Issue> imageContrast = filter(result.getIssues(), "ImageContrastCheck");
+
+            ExpectedLevels expectedLevels = new ExpectedLevels();
+            expectedLevels.expectedVerboses = 3;
+            expectedLevels.check(imageContrast);
+
+            // Make sure no other errors in the system.
+            imageContrast = filter(imageContrast, EnumSet.of(Level.ERROR, Level.WARNING));
+            List<Issue> filtered = filter(result.getIssues(), EnumSet.of(Level.ERROR, Level.WARNING));
+            checkEquals(filtered, imageContrast);
+        }, false);
+    }
+
+    @Test
+    public void testTouchTargetSizeCheck() throws Exception {
+        render("a11y_test_touch_target_size.xml", session -> {
+            ValidatorResult result = getRenderResult(session);
+            List<Issue> targetSizes = filter(result.getIssues(), "TouchTargetSizeCheck");
+
+            ExpectedLevels expectedLevels = new ExpectedLevels();
+            expectedLevels.expectedErrors = 5;
+            expectedLevels.expectedVerboses = 1;
+            expectedLevels.check(targetSizes);
+
+            // Make sure no other errors in the system.
+            targetSizes = filter(targetSizes, EnumSet.of(Level.ERROR));
+            List<Issue> filtered = filter(result.getIssues(), EnumSet.of(Level.ERROR));
+            checkEquals(filtered, targetSizes);
+        });
+    }
+
+    private void checkEquals(List<Issue> list1, List<Issue> list2) {
+        assertEquals(list1.size(), list2.size());
+        for (int i = 0; i < list1.size(); i++) {
+            assertEquals(list1.get(i), list2.get(i));
+        }
+    }
+
+    private List<Issue> filter(List<ValidatorData.Issue> results, EnumSet<Level> errors) {
+        return results.stream().filter(
+                issue -> errors.contains(issue.mLevel)).collect(Collectors.toList());
+    }
+
+    private List<Issue> filter(
+            List<ValidatorData.Issue> results, String sourceClass) {
+        return results.stream().filter(
+                issue -> sourceClass.equals(issue.mSourceClass)).collect(Collectors.toList());
+    }
+
+    private ValidatorResult getRenderResult(RenderSession session) {
+        Object validationData = session.getValidationData();
+        assertNotNull(validationData);
+        assertTrue(validationData instanceof ValidatorResult);
+        return (ValidatorResult) validationData;
+    }
+    private void render(String fileName, RenderSessionListener verifier) throws Exception {
+        render(fileName, verifier, true);
+    }
+
+    private void render(
+            String fileName,
+            RenderSessionListener verifier,
+            boolean enableImageCheck) throws Exception {
+        LayoutValidator.updatePolicy(new Policy(
+                EnumSet.of(Type.ACCESSIBILITY, Type.RENDER),
+                EnumSet.of(Level.ERROR, Level.WARNING, Level.INFO, Level.VERBOSE)));
+
+        LayoutPullParser parser = createParserFromPath(fileName);
+        LayoutLibTestCallback layoutLibCallback =
+                new LayoutLibTestCallback(getLogger(), mDefaultClassLoader);
+        layoutLibCallback.initResources();
+        SessionParamsBuilder params = getSessionParamsBuilder()
+                .setParser(parser)
+                .setConfigGenerator(ConfigGenerator.NEXUS_5)
+                .setCallback(layoutLibCallback)
+                .disableDecoration()
+                .enableLayoutValidation();
+
+        if (enableImageCheck) {
+            params.enableLayoutValidationImageCheck();
+        }
+
+        render(sBridge, params.build(), -1, verifier);
+    }
+
+    /**
+     * Helper class that checks the list of issues..
+     */
+    private static class ExpectedLevels {
+        // Number of errors expected
+        public int expectedErrors = 0;
+        // Number of warnings expected
+        public int expectedWarnings = 0;
+        // Number of infos expected
+        public int expectedInfos = 0;
+        // Number of verboses expected
+        public int expectedVerboses = 0;
+
+        public void check(List<Issue> issues) {
+            int errors = 0;
+            int warnings = 0;
+            int infos = 0;
+            int verboses = 0;
+
+            for (Issue issue : issues) {
+                switch (issue.mLevel) {
+                    case ERROR:
+                        errors++;
+                        break;
+                    case WARNING:
+                        warnings++;
+                        break;
+                    case INFO:
+                        infos++;
+                        break;
+                    case VERBOSE:
+                        verboses++;
+                        break;
+                }
+            }
+
+            assertEquals("Number of expected errors", expectedErrors, errors);
+            assertEquals("Number of expected warnings",expectedWarnings, warnings);
+            assertEquals("Number of expected infos", expectedInfos, infos);
+            assertEquals("Number of expected verboses", expectedVerboses, verboses);
+
+            int size = expectedErrors + expectedWarnings + expectedInfos + expectedVerboses;
+            assertEquals("expected size", size, issues.size());
+        }
+    };
+}
diff --git a/create/src/com/android/tools/layoutlib/create/Main.java b/create/src/com/android/tools/layoutlib/create/Main.java
index 4636a1c..b56416e 100644
--- a/create/src/com/android/tools/layoutlib/create/Main.java
+++ b/create/src/com/android/tools/layoutlib/create/Main.java
@@ -134,6 +134,8 @@
                         "android.annotation.Nullable",      // annotations
                         "com.android.internal.transition.EpicenterTranslateClipReveal",
                         "com.android.internal.graphics.drawable.AnimationScaleListDrawable",
+                        "com.google.android.apps.common.testing.accessibility.**",
+                        "com.google.android.libraries.accessibility.**",
                     },
                     info.getExcludedClasses(),
                     new String[] {
diff --git a/remote/client/src/com/android/layoutlib/bridge/remote/client/adapters/RemoteLayoutlibCallbackAdapter.java b/remote/client/src/com/android/layoutlib/bridge/remote/client/adapters/RemoteLayoutlibCallbackAdapter.java
index f796f3d..01efd12 100644
--- a/remote/client/src/com/android/layoutlib/bridge/remote/client/adapters/RemoteLayoutlibCallbackAdapter.java
+++ b/remote/client/src/com/android/layoutlib/bridge/remote/client/adapters/RemoteLayoutlibCallbackAdapter.java
@@ -56,11 +56,6 @@
     }
 
     @Override
-    public String getNamespace() {
-        return mDelegate.getNamespace();
-    }
-
-    @Override
     public ResourceReference resolveResourceId(int id) {
         return mDelegate.resolveResourceId(id);
     }
diff --git a/remote/common/src/com/android/layout/remote/api/RemoteLayoutlibCallback.java b/remote/common/src/com/android/layout/remote/api/RemoteLayoutlibCallback.java
index c8d2ded..d68934a 100644
--- a/remote/common/src/com/android/layout/remote/api/RemoteLayoutlibCallback.java
+++ b/remote/common/src/com/android/layout/remote/api/RemoteLayoutlibCallback.java
@@ -34,8 +34,6 @@
     Object loadView(String name, Class[] constructorSignature, Object[] constructorArgs)
             throws Exception;
 
-    String getNamespace() throws RemoteException;
-
     ResourceReference resolveResourceId(int id) throws RemoteException;
 
     int getOrGenerateResourceId(ResourceReference resource) throws RemoteException;
diff --git a/remote/server/src/com/android/layoutlib/bridge/remote/server/adapters/RemoteLayoutlibCallbackAdapter.java b/remote/server/src/com/android/layoutlib/bridge/remote/server/adapters/RemoteLayoutlibCallbackAdapter.java
index 51772e7..719de4d 100644
--- a/remote/server/src/com/android/layoutlib/bridge/remote/server/adapters/RemoteLayoutlibCallbackAdapter.java
+++ b/remote/server/src/com/android/layoutlib/bridge/remote/server/adapters/RemoteLayoutlibCallbackAdapter.java
@@ -157,15 +157,6 @@
     }
 
     @Override
-    public String getNamespace() {
-        try {
-            return mDelegate.getNamespace();
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    @Override
     public ResourceReference resolveResourceId(int id) {
         try {
             return mDelegate.resolveResourceId(id);
diff --git a/validator/Android.bp b/validator/Android.bp
index e55a433..0eff99b 100644
--- a/validator/Android.bp
+++ b/validator/Android.bp
@@ -28,13 +28,8 @@
     ],
 
     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
index 380a727..af7d020 100644
--- a/validator/resources/strings.properties
+++ b/validator/resources/strings.properties
@@ -55,8 +55,6 @@
 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
diff --git a/validator/resources/values.xml b/validator/resources/values.xml
new file mode 100644
index 0000000..ae49a3c
--- /dev/null
+++ b/validator/resources/values.xml
@@ -0,0 +1,133 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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.
+  -->
+<resources xmlns:ns1="urn:oasis:names:tc:xliff:document:1.2">
+    <string description="Describes a UI element on which an action may be performed by the user [CHAR LIMIT=NONE]" name="actionable">actionable</string>
+    <string description="The term for a UI element that functions as a button. [CHAR LIMIT=NONE]" name="button_item_type">button</string>
+    <string description="The title of a check on the accessiblity traversal constraints on the elements in a view. [CHAR LIMIT=50]" name="check_title_accessibility_traversal">Traversal order</string>
+    <string description="The title of a check describing that the class name is not supported by the accessibility service. [CHAR LIMIT=50]" name="check_title_class_name_not_supported">Unsupported item type</string>
+    <string description="The title of a check describing that views should use the android concept of a &apos;URLSpan&apos; instead of a &apos;ClickableSpan&apos;, for improved accessibility. [CHAR LIMIT=50]" name="check_title_clickablespan">Link</string>
+    <string description="The title of a check describing that multiple clickable views (UI elements) share the exact same space on the screen. [CHAR LIMIT=50]" name="check_title_duplicate_clickable_bounds">Clickable items</string>
+    <string description="The title of a check describing that this view (UI element) has the same text to be spoken by a screen reader as another view on the screen. [CHAR LIMIT=50]" name="check_title_duplicate_speakable_text">Item descriptions</string>
+    <string description="The title of a check describing that this editable view (UI element) should not populate its &apos;android:contentDescription&apos; attribute. [CHAR LIMIT=50]" name="check_title_editable_content_desc">Editable item label</string>
+    <string description="The title of a check describing that the contrast ratio (the ratio of the luminance of the foreground and background colors) of the image in this view (UI element) is lower than the required ratio. [CHAR LIMIT=50]" name="check_title_image_contrast">Image contrast</string>
+    <string description="The title of a check describing that UI elements may be unexposed to accessibility services [CHAR LIMIT=NONE]" name="check_title_item_exposed">Exposed items</string>
+    <string description="The title of a check on link text. [CHAR LIMIT=50]" name="check_title_link_test">Link text</string>
+    <string description="The title of a check used to determine readability of text based on reading score. [CHAR LIMIT=50]" name="check_title_reading_score">Readability</string>
+    <string description="The title of a check describing that this view (UI element) has redundant or unnecessary text within its &apos;android:contentDescription&apos; attribute. [CHAR LIMIT=50]" name="check_title_redundant_description">Item type label</string>
+    <string description="The title of a check describing that this View (UI element) has no description that would be spoken to the user by a screen reader if this view were to be focused. [CHAR LIMIT=50]" name="check_title_speakable_text_present">Item label</string>
+    <string description="The title of a check describing that the contrast ratio (the ratio of the luminance of the foreground and background colors) of this TextView (UI element) is lower than the required ratio. [CHAR LIMIT=50]" name="check_title_text_contrast">Text contrast</string>
+    <string description="The title of a check on the styling of text. [CHAR LIMIT=50]" name="check_title_text_style">Text Style</string>
+    <string description="The title of a check describing that the size of this clickable view (UI element) is below minimum requirements. [CHAR LIMIT=50]" name="check_title_touch_target_size">Touch target</string>
+    <string description="The title of a check used to detect banned words within the text of a view. [CHAR LIMIT=50]" name="check_view_banned_word">Banned word</string>
+    <string description="Describes a UI element that is clickable [CHAR LIMIT=NONE]" name="clickable">clickable</string>
+    <string description="Describes a UI element that is both clickable and long clickable [CHAR LIMIT=NONE]" name="clickable_and_long_clickable">clickable and long clickable</string>
+    <string description="Describes italic text styling. [CHAR LIMIT=NONE]" name="italic_text">italic</string>
+    <string description="Describes text with both italic and underlined styling. [CHAR LIMIT=NONE]" name="italic_underline_text">italic and underline</string>
+    <string description="Describes a UI element that is long clickable [CHAR LIMIT=NONE]" name="long_clickable">long clickable</string>
+    <string description="Describes a UI element that is not clickable [CHAR LIMIT=NONE]" name="non_clickable">non-clickable</string>
+    <string description="The question message for question of if the foreground and background colors are correct [CHAR LIMIT=NONE]" name="question_id_message_confirm_foreground_background_colors">Are the detected foreground and background colors correct?</string>
+    <string description="The question prompting a user to provide a background color [CHAR LIMIT=NONE]" name="question_id_message_provide_background_color">What is the correct background color?</string>
+    <string description="The question prompting a user to provide a foreground color [CHAR LIMIT=NONE]" name="question_id_message_provide_foreground_color">What is the correct foreground color?</string>
+    <string description="The question message for question prompting the identification of screen regions with unexposed elements [CHAR LIMIT=NONE]" name="question_message_identify_unexposed_items">Select regions of the screen with unidentified items.</string>
+    <string description="The question message for question of if there are unexposed elements in a view [CHAR LIMIT=NONE]" name="question_message_screen_has_unexposed_items">Does this screen contain important items that are not outlined?</string>
+    <string description="The user selection option for if only the background color is incorrect. [CHAR LIMIT=NONE]" name="question_option_message_background_incorrect">Background incorrect</string>
+    <string description="The user selection option for if the foreground and background colors are both correct [CHAR LIMIT=NONE]" name="question_option_message_both_correct">Both correct</string>
+    <string description="The user selection option for if the foreground and background colors are incorrect.[CHAR LIMIT=NONE]" name="question_option_message_both_incorrect">Foreground and background incorrect</string>
+    <string description="The user selection option for if only the foreground color is incorrect. [CHAR LIMIT=NONE]" name="question_option_message_foreground_incorrect">Foreground incorrect</string>
+    <string description="The user selection option for if it is unknown if the foreground and background colors are both incorrect.[CHAR LIMIT=NONE]" name="question_option_message_unknown">Unknown</string>
+    <string description="A message that is appended to a result message of a check indicating the view (UI element) may only be partially visible and is against the scrollable edge of a parent (a larger containing UI element). [CHAR LIMIT=NONE]" name="result_message_addendum_against_scrollable_edge">This item may be only partially visible within a scrollable container.</string>
+    <string description="A message that is appended to a result message of a check describing that the result may be ignored in the case where this view&apos;s (UI element) parent (a larger containing UI element) performs the same action of this view when clicked. [CHAR LIMIT=NONE]" name="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.</string>
+    <string description="A message that is appended to a result message of a check describing that this view&apos;s (UI element) parent (a containing UI element) is clipping (constraining in size) the size of this item. [CHAR LIMIT=NONE]" name="result_message_addendum_clipped_by_ancestor">A parent container may be clipping the size of this item, which has a drawing area of <ns1:g example="30dp" id="nonclipped_width">&lt;tt>%1$ddp&lt;/tt></ns1:g> x <ns1:g example="30dp" id="nonclipped_height">&lt;tt>%2$ddp&lt;/tt></ns1:g>. Consider increasing the size of this item\'s clipping ancestor, or allowing a larger parent container to handle actions on behalf of this item.</string>
+    <string description="A description of a view&apos;s (UI element&apos;s) opacity including level of translucency. [CHAR LIMIT=NONE]" name="result_message_addendum_opacity_description">Its actual opacity is <ns1:g example="50" id="opacity">%1$.2f</ns1:g>%%.</string>
+    <string description="A message that is appended to a result message of a check describing that the result may be inaccurate because this view (UI element) uses a &apos;TouchDelegate&apos;, which allows a developer to define their own touchable region for the view. [CHAR LIMIT=NONE]" name="result_message_addendum_touch_delegate">A <ns1:g example="TouchDelegate" id="touch_delegate_class">&lt;tt>TouchDelegate&lt;/tt></ns1:g> 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.</string>
+    <string description="A message that is appended to a result message of a check describing that the result may be inaccurate because this view (UI element) uses a &apos;TouchDelegate&apos;, which allows a developer to define their own touchable region for the view. [CHAR LIMIT=NONE]" name="result_message_addendum_touch_delegate_with_hit_rect">A <ns1:g example="TouchDelegate" id="touch_delegate_class">&lt;tt>TouchDelegate&lt;/tt></ns1:g> with size <ns1:g example="30dp" id="hit_rect_width">&lt;tt>%1$ddp&lt;/tt></ns1:g> x <ns1:g example="30dp" id="hit_rect_height">&lt;tt>%2$ddp&lt;/tt></ns1:g> has been detected for this item. Consider increasing the size of its hit <ns1:g example="Rect" id="rect_class">&lt;tt>Rect&lt;/tt></ns1:g>.</string>
+    <string description="A message that is appended to a result message of a check describing that the view (UI element) may be obscured by other on-screen content. [CHAR LIMIT=NONE]" name="result_message_addendum_view_potentially_obscured">This item may be obscured by other on-screen content. Consider manually testing this item\'s contrast.</string>
+    <string description="The result message of a check describing that this view&apos;s background is non-opaque/translucent. [CHAR LIMIT=NONE]" name="result_message_background_must_be_opaque">This items\'s background color is not opaque.</string>
+    <string description="The result message of a check describing that the word used in this string is inappropriate. [CHAR LIMIT=NONE]" name="result_message_banned_word">This item\'s text may contain an inappropriate word, "<ns1:g example="heck" id="banned_word">&lt;tt>%1$s&lt;/tt></ns1:g>"</string>
+    <string description="The brief result message describing an inappropriate word being used. [CHAR LIMIT=NONE]" name="result_message_brief_banned_word">Consider removing inappropriate words from this item\'s text</string>
+    <string description="The brief result message of a check describing that this view (UI element) has redundant or unnecessary text within its &apos;android:contentDescription&apos; attribute. [CHAR LIMIT=NONE]" name="result_message_brief_content_desc_contains_redundant_word">This item\'s <ns1:g example="android:contentDescription" id="content_description_attr">&lt;tt>android:contentDescription&lt;/tt></ns1:g> might contain unnecessary text.</string>
+    <string description="The brief result message of a check describing that the contrast ratio (the ratio of the luminance of the foreground and background colors) of the image in this view (UI element) is lower than the required ratio. [CHAR LIMIT=NONE]" name="result_message_brief_image_contrast_not_sufficient">Consider increasing the contrast ratio between this image\'s foreground and background.</string>
+    <string description="The brief result message of a check describing that an element is not exposed to accessibility services [CHAR LIMIT=NONE]" name="result_message_brief_is_unexposed_item_screen_region">Consider exposing items in this region to accessibility services.</string>
+    <string description="The brief result message of a check describing that link text is not descriptive. [CHAR LIMIT=NONE]" name="result_message_brief_link_text_not_descriptive">Consider using more descriptive text in the link.</string>
+    <string description="The brief result message if text has a low readability score. [CHAR LIMIT=NONE]" name="result_message_brief_low_reading_score">This text may have a low readability score.</string>
+    <string description="The brief result message of a check describing that multiple items (UI elements) share the same description that would be spoken by a screen reader. [CHAR LIMIT=NONE}" name="result_message_brief_same_speakable_text">Multiple items have the same description.</string>
+    <string description="The brief result message of a check describing that multiple actionable items (UI elements) share the same space on the screen. [CHAR LIMIT=NONE]" name="result_message_brief_same_view_bounds">Multiple <ns1:g example="clickable and long clickable" id="clickability">%1$s</ns1:g> items share this location on the screen.</string>
+    <string description="The brief result message of a check describing that the size of this view (UI element) may be too small to be touched or interacted with reliably. [CHAR LIMIT=NONE]" name="result_message_brief_small_touch_target">Consider making this clickable item larger.</string>
+    <string description="The brief message describing that using bold typeface is ideal. [CHAR LIMIT=NONE]" name="result_message_brief_styled_text">Consider removing <ns1:g example="italic" id="style_info">%1$s</ns1:g> styling on longer passages of text.</string>
+    <string description="The brief result message of a check describing that the contrast ratio (the ratio of the luminance of the foreground and background colors) of the text in this TextView (UI element) is lower than the required ratio. [CHAR LIMIT=NONE]" name="result_message_brief_text_contrast_not_sufficient">Consider increasing this item\'s text foreground to background contrast ratio.</string>
+    <string description="The brief result message of a check describing that this view may be presented incorrectly to the user when traversed with a screen reader. [CHAR LIMIT=NONE]" name="result_message_brief_unpredictable_traversal">Traversal behavior with screen readers may be unpredictable.</string>
+    <string description="The result message of a check describing that the class name is empty and not supported by the accessibility service. [CHAR LIMIT=NONE]" name="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.</string>
+    <string description="The result message of a check describing that the class name is unknown. [CHAR LIMIT=NONE]" name="result_message_class_name_is_unknown">This item\'s type could not be determined.</string>
+    <string description="The result message of a check describing that the class name is not supported by the accessibility service. [CHAR LIMIT=NONE]" name="result_message_class_name_not_supported_brief">This item\'s type may not be supported.</string>
+    <string description="The result message of a check describing that the class name is not supported by the accessibility service. [CHAR LIMIT=NONE]" name="result_message_class_name_not_supported_detail">This item\'s type <ns1:g example="com.example.MyButton" id="class_name">&lt;tt>%1$s&lt;/tt></ns1:g> may not be resolvable by accessibility services. Consider using a type defined by the Android SDK.</string>
+    <string description="The result message of a check describing the specific android class of the view (UI element) could not be determined. [CHAR LIMIT=NONE]" name="result_message_clickablespan_no_determined_type">This item\'s type is undetermined.</string>
+    <string description="The result message of a check stating that a description of a view (UI element) has redundant or unnecessary text (ex: a view of type Button whose &apos;android:contentDescription&apos; is &apos;Save button&apos;). [CHAR LIMIT=NONE]" name="result_message_content_desc_contains_redundant_word">This item\'s <ns1:g example="android:contentDescription" id="content_description_attr">&lt;tt>android:contentDescription&lt;/tt></ns1:g>, \"<ns1:g example="Save button" id="content_desc">&lt;tt>%1$s&lt;/tt></ns1:g>\" contains the item type \"<ns1:g example="button" id="item_type">&lt;tt>%2$s&lt;/tt></ns1:g>\".</string>
+    <string description="The result message of a check stating that a description of a view (UI element) ends with that view&apos;s type (ex: a view of type Button whose &apos;android:contentDescription&apos; is &apos;Save button&apos;). [CHAR LIMIT=NONE]" name="result_message_content_desc_ends_with_view_type">This item\'s <ns1:g example="android:contentDescription" id="content_description_attr">&lt;tt>android:contentDescription&lt;/tt></ns1:g>, \"<ns1:g example="Save button" id="content_desc">&lt;tt>%1$s&lt;/tt></ns1:g>\" ends with the item\'s type.</string>
+    <string description="The result message of a check describing that the background color of a view (UI element) could not be determined. [CHAR LIMIT=NONE]" name="result_message_could_not_get_background_color">This item\'s background color could not be determined.</string>
+    <string description="The result message of a check describing that the color of the text within a view (UI element) could not be determined. [CHAR LIMIT=NONE]" name="result_message_could_not_get_text_color">This item\'s text color could not be determined.</string>
+    <string description="The result message of a check describing that the height of this view (UI element) is below the user-defined minimum requirement. [CHAR LIMIT=NONE]" name="result_message_customized_small_touch_target_height">This item\'s height is <ns1:g example="30dp" id="view_height">&lt;tt>%1$ddp&lt;/tt></ns1:g>. Consider increasing the height of this touch target to at least the configured minimum height of <ns1:g example="48dp" id="recommended_minimum_height">&lt;tt>%2$ddp&lt;/tt></ns1:g>.</string>
+    <string description="The result message of a check describing that the width of this view (UI element) is below the user-defined minimum requirement. [CHAR LIMIT=NONE]" name="result_message_customized_small_touch_target_width">This item\'s width is <ns1:g example="30dp" id="view_width">&lt;tt>%1$ddp&lt;/tt></ns1:g>. Consider increasing the width of this touch target to at least the configured minimum width of <ns1:g example="48dp" id="recommended_minimum_width">&lt;tt>%2$ddp&lt;/tt></ns1:g>.</string>
+    <string description="The result message of a check describing that the width and height of this view (UI element) are both below user-defined minimum requirements. [CHAR LIMIT=NONE]" name="result_message_customized_small_touch_target_width_and_height">This item\'s size is <ns1:g example="30dp" id="view_width">&lt;tt>%1$ddp&lt;/tt></ns1:g> x <ns1:g example="30dp" id="view_height">&lt;tt>%2$ddp&lt;/tt></ns1:g>. Consider increasing this touch target to at least the configured minimum size of <ns1:g example="32dp" id="recommended_view_width">&lt;tt>%3$ddp&lt;/tt></ns1:g> x <ns1:g example="32dp" id="recommended_view_height">&lt;tt>%4$ddp&lt;/tt></ns1:g>.</string>
+    <string description="The result message of a check describing that an event can be disruptive to the user. [CHAR LIMIT=NONE]" name="result_message_disruptive_announcement">A disruptive accessibility announcement has been used.</string>
+    <string description="The result message of a check describing that this editable view (UI element) should not populate its &apos;android:contentDescription&apos; attribute. [CHAR LIMIT=NONE]" name="result_message_editable_textview_content_desc">This editable <ns1:g example="TextView" id="text_view_class">&lt;tt>TextView&lt;/tt></ns1:g> has an <ns1:g example="android:contentDescription" id="content_description_tag">&lt;tt>android:contentDescription&lt;/tt></ns1:g>. A screen reader may read this attribute instead of the editable content when the user is navigating.</string>
+    <string description="The result message of a check describing that this check can only be run in English locales. [CHAR LIMIT=NONE]" name="result_message_english_locale_only">This check only runs on devices with locales set to English.</string>
+    <string description="The result message if user was uncertain if a screen has any UI elements that were not exposed properly to accessibility services. [CHAR LIMIT=NONE]" name="result_message_has_unexposed_items">This screen may have items that are not exposed to accessibility services.</string>
+    <string description="The result message of a check describing that the contrast ratio (the ratio of the luminance of the foreground and background colors) of the image in this view (UI element) is lower than the required ratio. [CHAR LIMIT=NONE]" name="result_message_image_contrast_not_sufficient">The image\'s contrast ratio is <ns1:g example="2.9" id="contrast_ratio">%1$.2f</ns1:g>. This ratio is based on an estimated foreground color of <ns1:g example="#000000" id="foreground_color">&lt;tt>#%3$06X&lt;/tt></ns1:g> and an estimated background color of <ns1:g example="#FFFFFF" id="background_color">&lt;tt>#%4$06X&lt;/tt></ns1:g>. Consider increasing this ratio to <ns1:g example="3.0" id="recommended_contrast_ratio">%2$.2f</ns1:g> or greater.</string>
+    <string description="The result message of a check describing that the contrast ratio (the ratio of the luminance of the foreground and background colors) of the image in this view (UI element) is lower than a user-defined ratio. [CHAR LIMIT=NONE]" name="result_message_image_customized_contrast_not_sufficient">The image\'s contrast ratio is <ns1:g example="2.9" id="contrast_ratio">%1$.2f</ns1:g>. This ratio is based on an estimated foreground color of <ns1:g example="#000000" id="foreground_color">&lt;tt>#%3$06X&lt;/tt></ns1:g> and an estimated background color of <ns1:g example="#FFFFFF" id="background_color">&lt;tt>#%4$06X&lt;/tt></ns1:g>. Consider increasing this ratio to the configured ratio of <ns1:g example="3.0" id="customized_heuristic_contrast_ratio">%2$.2f</ns1:g> or greater.</string>
+    <string description="The result message if a screen region contains an unexposed element [CHAR LIMIT=NONE]" name="result_message_is_unexposed_item_screen_region">The region with on-screen location <ns1:g example="[0,0][1920,1080]" id="region_bounds">&lt;tt>%1$s&lt;/tt></ns1:g> contains at least one item that is not exposed to accessibility services.</string>
+    <string description="The result message indicating that the user must provide more information to determine if all UI elements within a view hierarchy are exposed properly to accessibility services. [CHAR LIMIT=NONE]" name="result_message_item_exposed_needs_manual_assessment">This screen needs manual inspection to ensure all items are exposed to accessibility services.</string>
+    <string description="The result message of a check describing that link text is not descriptive. [CHAR LIMIT=NONE]" name="result_message_link_text_not_descriptive">The link text \"<ns1:g example="This is an arbitrary string." id="link_text">&lt;tt>%1$s&lt;/tt></ns1:g>\" may not independently convey the link\'s purpose.</string>
+    <string description="The full result message if text has a low readability score. [CHAR LIMIT=NONE]" name="result_message_low_reading_score">This item\'s text has an approximate readability score of <ns1:g example="32" id="text_reading_score">%1$.0f</ns1:g>, which is lower than the recommended score of <ns1:g example="70" id="target_reading_score">%2$.0f</ns1:g>. Consider using simpler words or sentences to make the text easier to read.</string>
+    <string description="The result message of a check describing that this View (UI element) has no description that would be spoken to the user by a screen reader if this view were to be focused. [CHAR LIMIT=NONE]" name="result_message_missing_speakable_text">This item may not have a label readable by screen readers.</string>
+    <string description="The result message of a check describing that this view (UI element) does not have any text set for the android contentDescription attribute. [CHAR LIMIT=NONE]" name="result_message_no_content_desc">This item has no <ns1:g example="android:contentDescription" id="content_description_attr">&lt;tt>android:contentDescription&lt;/tt></ns1:g>.</string>
+    <string description="The result message of a check describing that we were unable to obtain a screenshot. [CHAR LIMIT=NONE]" name="result_message_no_screencapture">Screen capture data could not be obtained.</string>
+    <string description="The message if this check was unable to get typeface info for a TextView. [CHAR LIMIT=NONE]" name="result_message_no_typeface_info">This item\'s typeface could not be determined.</string>
+    <string description="The result message of a check describing that this view (UI element) is not clickable. [CHAR LIMIT=NONE]" name="result_message_not_clickable">This view is not clickable.</string>
+    <string description="The result message of a check describing that this view (UI element) does not contain editable text content. [CHAR LIMIT=NONE]" name="result_message_not_editable_textview">This item is not an editable <ns1:g example="TextView" id="text_view_class">&lt;tt>TextView&lt;/tt></ns1:g>.</string>
+    <string description="The result message of a check describing that this view (UI element) is in a &apos;not enabled&apos; or &apos;disabled&apos; state. [CHAR LIMIT=NONE]" name="result_message_not_enabled">This item isn\'t enabled.</string>
+    <string description="The result message of a check describing that this view (UI element) is not an instance of the android class ImageView. [CHAR LIMIT=NONE]" name="result_message_not_imageview">This item is not an <ns1:g example="ImageView" id="image_view_class">&lt;tt>ImageView&lt;/tt></ns1:g>.</string>
+    <string description="The result message of a check describing that this view (UI element) is not exposed to a screen reader or other accessibility service. [CHAR LIMIT=NONE]" name="result_message_not_important_for_accessibility">This item was not found to be important for accessibility.</string>
+    <string description="The result message of a check describing that this view (UI element) is not an instance of the android TextView class [CHAR LIMIT=NONE]" name="result_message_not_text_view">This item is not a <ns1:g example="TextView" id="text_view_class">&lt;tt>TextView&lt;/tt></ns1:g>.</string>
+    <string description="The result message of a check describing that this view (UI element) is not currently visible to the user. [CHAR LIMIT=NONE]" name="result_message_not_visible">This item is not visible.</string>
+    <string description="The result message of a check describing that this view (UI element) has the same text to be spoken by a screen reader as another view which has the same clickability. [CHAR LIMIT=NONE]" name="result_message_same_speakable_text">This <ns1:g example="clickable" id="clickability">%1$s</ns1:g> item\'s speakable text: \"<ns1:g example="This is an arbitrary string." id="speakable_text">&lt;tt>%2$s&lt;/tt></ns1:g>\" is identical to that of <ns1:g example="2" id="num_views">%3$d</ns1:g> other item(s).</string>
+    <string description="The result message of a check describing that this view (UI element) shares exact same space on the screen as another view which has the same clickability and long clickability. [CHAR LIMIT=NONE]" name="result_message_same_view_bounds">This <ns1:g example="clickable and long clickable" id="clickability">%1$s</ns1:g> item has the same on-screen location (<ns1:g example="[0,0][100,100]" id="view_bounds">&lt;tt>%2$s&lt;/tt></ns1:g>) as <ns1:g example="2" id="num_views">%3$d</ns1:g> other item(s) with those properties.</string>
+    <string description="The result message of a check describing that the screenshot of a view (UI element) was hidden. [CHAR LIMIT=NONE]" name="result_message_screencapture_data_hidden">Screen capture information for this item was hidden.</string>
+    <string description="The result message of a check describing that the screenshot of a view (UI element) has a uniform color. [CHAR LIMIT=NONE]" name="result_message_screencapture_uniform_color">Screen capture has a uniform color.</string>
+    <string description="The result message of a check describing that the check is not applicable since specific Android SDK version. [CHAR LIMIT=NONE]" name="result_message_sdk_version_not_applicable">This check is not applicable on devices running Android <ns1:g example="8.0" id="android_version">%1$s</ns1:g> and above.</string>
+    <string description="The result message if text is too short to run a check on. [CHAR LIMIT=NONE]" name="result_message_short_text">This item\'s text is too short to be evaluated.</string>
+    <string description="The result message of a check describing that a screen reader would not focus this view (UI element). [CHAR LIMIT=NONE]" name="result_message_should_not_focus">This item would not be focused by a screen reader.</string>
+    <string description="The result message of a check describing that the height of this view (UI element) is below the minimum requirement. [CHAR LIMIT=NONE]" name="result_message_small_touch_target_height">This item\'s height is <ns1:g example="30dp" id="view_height">&lt;tt>%1$ddp&lt;/tt></ns1:g>. Consider making the height of this touch target <ns1:g example="48dp" id="recommended_minimum_height">&lt;tt>%2$ddp&lt;/tt></ns1:g> or larger.</string>
+    <string description="The result message of a check describing that the width of this view (UI element) is below the minimum requirement. [CHAR LIMIT=NONE]" name="result_message_small_touch_target_width">This item\'s width is <ns1:g example="30dp" id="view_width">&lt;tt>%1$ddp&lt;/tt></ns1:g>. Consider making the width of this touch target <ns1:g example="48dp" id="recommended_minimum_width">&lt;tt>%2$ddp&lt;/tt></ns1:g> or larger.</string>
+    <string description="The result message of a check describing that the width and height of this view (UI element) are both below minimum requirements. [CHAR LIMIT=NONE]" name="result_message_small_touch_target_width_and_height">This item\'s size is <ns1:g example="30dp" id="view_width">&lt;tt>%1$ddp&lt;/tt></ns1:g> x <ns1:g example="30dp" id="view_height">&lt;tt>%2$ddp&lt;/tt></ns1:g>. Consider making this touch target <ns1:g example="32dp" id="recommended_view_width">&lt;tt>%3$ddp&lt;/tt></ns1:g> wide and <ns1:g example="32dp" id="recommended_view_height">&lt;tt>%4$ddp&lt;/tt></ns1:g> high or larger.</string>
+    <string description="The result message of a check describing the text that would be spoken to the user by a screen reader if this view (UI element) were to be focused. [CHAR LIMIT=NONE]" name="result_message_speakable_text">This <ns1:g example="clickable and long clickable" id="clickability">%1$s</ns1:g> item also has speakable text: \"<ns1:g example="This is an arbitrary string." id="speakable_text">&lt;tt>%2$s&lt;/tt></ns1:g>\".</string>
+    <string description="The full result message if text uses italic style. [CHAR LIMIT=NONE]" name="result_message_styled_text">This item may use <ns1:g example="italic" id="style_info">%1$s</ns1:g> font for a long passage of text. Consider removing the style from the font to improve readability.</string>
+    <string description="The result message of a check describing that this view&apos;s text is non-opaque/translucent. [CHAR LIMIT=NONE]" name="result_message_text_must_be_opaque">This item\'s text color is not opaque.</string>
+    <string description="The result message of a check describing that the contrast ratio (the ratio of the luminance of the foreground and background colors) of this TextView (UI element) is lower than the required ratio. [CHAR LIMIT=NONE]" name="result_message_textview_contrast_not_sufficient">The item\'s text contrast ratio is <ns1:g example="2.9" id="contrast_ratio">%1$.2f</ns1:g>. This ratio is based on a text color of <ns1:g example="#000000" id="text_color">&lt;tt>#%2$06X&lt;/tt></ns1:g> and background color of <ns1:g example="#FFFFFF" id="background_color">&lt;tt>#%3$06X&lt;/tt></ns1:g>. Consider increasing this item\'s text contrast ratio to <ns1:g example="3.0" id="recommended_contrast_ratio">%4$.2f</ns1:g> or greater.</string>
+    <string description="The result message of a check describing that this TextView (UI element) has no text. [CHAR LIMIT=NONE]" name="result_message_textview_empty">This <ns1:g example="TextView" id="text_view_class">&lt;tt>TextView&lt;/tt></ns1:g> is empty.</string>
+    <string description="The result message of a check describing that the contrast ratio (the ratio of the luminance of the foreground and background colors) of this TextView (UI element) is lower than the required ratio unless its text is considered to be large. [CHAR LIMIT=NONE]" name="result_message_textview_heuristic_contrast_not_sufficient">The item\'s text contrast ratio is <ns1:g example="2.9" id="contrast_ratio">%1$.2f</ns1:g>. This ratio is based on an estimated foreground color of <ns1:g example="#FFFFFF" id="foreground_color">&lt;tt>#%2$06X&lt;/tt></ns1:g> and an estimated background color of <ns1:g example="#000000" id="background_color">&lt;tt>#%3$06X&lt;/tt></ns1:g>. Consider using colors that result in a contrast ratio greater than <ns1:g example="4.5" id="recommended_contrast_ratio">%4$.2f</ns1:g> for small text, or <ns1:g example="3.0" id="tolerant_contrast_ratio">%5$.2f</ns1:g> for large text.</string>
+    <string description="The result message of a check describing that the contrast ratio (the ratio of the luminance of the foreground and background colors) of this TextView (UI element) is lower than the required ratio unless its text is considered to be large. Result based on colors obtained or confirmed through questions. [CHAR LIMIT=NONE]" name="result_message_textview_heuristic_contrast_not_sufficient_confirmed">The item\'s text contrast ratio is <ns1:g example="2.9" id="contrast_ratio">%1$.2f</ns1:g>. This ratio is based on the provided foreground color of <ns1:g example="#FFFFFF" id="foreground_color">&lt;tt>#%2$06X&lt;/tt></ns1:g> and provided background color of <ns1:g example="#000000" id="background_color">&lt;tt>#%3$06X&lt;/tt></ns1:g>. Consider using colors that result in a contrast ratio greater than <ns1:g example="4.5" id="recommended_contrast_ratio">%4$.2f</ns1:g> for small text, or <ns1:g example="3.0" id="tolerant_contrast_ratio">%5$.2f</ns1:g> for large text.</string>
+    <string description="The result message of a check describing that the contrast ratio (the ratio of the luminance of the foreground and background colors) of this TextView (UI element) is lower than a user-defined ratio. [CHAR LIMIT=NONE]" name="result_message_textview_heuristic_customized_contrast_not_sufficient">The item\'s text contrast ratio is <ns1:g example="2.9" id="contrast_ratio">%1$.2f</ns1:g>. This ratio is based on an estimated foreground color of <ns1:g example="#FFFFFF" id="foreground_color">&lt;tt>#%2$06X&lt;/tt></ns1:g> and an estimated background color of <ns1:g example="#000000" id="background_color">&lt;tt>#%3$06X&lt;/tt></ns1:g>. Consider increasing this item\'s text contrast ratio to the configured ratio of <ns1:g example="3.0" id="customized_heuristic_contrast_ratio">%4$.2f</ns1:g> or greater.</string>
+    <string description="The result message of a check describing that the contrast ratio (the ratio of the luminance of the foreground and background colors) of this TextView (UI element) is lower than a user-defined ratio based on user provided colors. [CHAR LIMIT=NONE]" name="result_message_textview_heuristic_customized_contrast_not_sufficient_confirmed">The item\'s text contrast ratio is <ns1:g example="2.9" id="contrast_ratio">%1$.2f</ns1:g>. This ratio is based on the provided foreground color of <ns1:g example="#FFFFFF" id="foreground_color">&lt;tt>#%2$06X&lt;/tt></ns1:g> and provided background color of <ns1:g example="#000000" id="background_color">&lt;tt>#%3$06X&lt;/tt></ns1:g>. Consider increasing this item\'s text contrast ratio to the configured ratio of <ns1:g example="3.0" id="customized_heuristic_contrast_ratio">%4$.2f</ns1:g> or greater.</string>
+    <string description="The result message of a check describing that this view (UI element) may be presented incorrectly to the user when traversed with a screen reader. [CHAR LIMIT=NONE]" name="result_message_traversal_cycle">This item may be part of a traversal ordering cycle due to its <ns1:g example="android:accessibilityTraversalAfter" id="traversal_after_attr">&lt;tt>%1$s&lt;/tt></ns1:g> attribute.  Traversal behavior with screen readers may be unpredictable.</string>
+    <string description="The result message of a check describing that this view (UI element) may be presented incorrectly to the user when traversed with a screen reader. [CHAR LIMIT=NONE]" name="result_message_traversal_over_constrained">Traversal ordering for this item may be over constrained based on its <ns1:g example="android:accessibilityTraversalBefore" id="traversal_before_attr">&lt;tt>android:accessibilityTraversalBefore&lt;/tt></ns1:g> and <ns1:g example="android:accessibilityTraversalAfter" id="traversal_after_attr">&lt;tt>android:accessibilityTraversalAfter&lt;/tt></ns1:g> attributes. Traversal behavior with screen readers may be unpredictable.</string>
+    <string description="The result message of a check describing that the view has text marked up with an android URLSpan (a hyperlink), which has an invalid URL. [CHAR LIMIT=NONE]" name="result_message_urlspan_invalid_url">Verify that the URL within this item\'s <ns1:g example="URLSpan" id="url_span_class">&lt;tt>URLSpan&lt;/tt></ns1:g> is valid.</string>
+    <string description="The result message of a check describing that views should use the android concept of a &apos;URLSpan&apos; instead of a &apos;ClickableSpan&apos;, for improved accessibility. [CHAR LIMIT=NONE]" name="result_message_urlspan_not_clickablespan">This item should use a <ns1:g example="URLSpan" id="url_span_class">&lt;tt>URLSpan&lt;/tt></ns1:g> in place of a <ns1:g example="ClickableSpan" id="clickable_span_class">&lt;tt>ClickableSpan&lt;/tt></ns1:g>.</string>
+    <string description="The result message of a check describing the position of this view (UI element) on the screen." name="result_message_view_bounds">This <ns1:g example="clickable and long clickable" id="clickability">%1$s</ns1:g> item also has an on-screen location of <ns1:g example="[0,0][100,100]" id="view_bounds">&lt;tt>%2$s&lt;/tt></ns1:g>.</string>
+    <string description="The result message of a check describing that all or part of the view (UI element) was off the screen when the screenshot was taken. [CHAR LIMIT=NONE]" name="result_message_view_not_within_screencapture">This item\'s on-screen location (<ns1:g example="[0,0][100,100]" id="view_bounds">&lt;tt>%1$s&lt;/tt></ns1:g>) were not within the screen capture on-screen location (<ns1:g example="[0,0][1920,1080]" id="capture_bounds">&lt;tt>%2$s&lt;/tt></ns1:g>).</string>
+    <string description="The result message of a check describing that web content (UI element shown within a browser) was not evaluated. [CHAR LIMIT=NONE]" name="result_message_web_content">Web content is not evaluated.</string>
+    <string description="Describes underlined text styling. [CHAR LIMIT=NONE]" name="underline_text">underline</string>
+</resources>
\ No newline at end of file
diff --git a/validator/src/ResourceConverter.java b/validator/src/ResourceConverter.java
new file mode 100644
index 0000000..18ffda8
--- /dev/null
+++ b/validator/src/ResourceConverter.java
@@ -0,0 +1,128 @@
+/*
+ * 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.
+ */
+
+import com.android.tools.layoutlib.annotations.Nullable;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+
+public class ResourceConverter {
+
+    /**
+     * Convert the Android strings.xml into generic Java strings.properties.
+     */
+    public static void main(String[] args) throws Exception {
+        System.out.println("Parsing input...");
+        Map<String, String> map = loadStrings("./validator/resources/values.xml");
+        System.out.println("Writing to output...");
+        writeStrings(map, "./validator/resources/strings.properties");
+        System.out.println("Finished converting.");
+    }
+
+    /**
+     * Writes <name, value> pair to outputPath.
+     */
+    private static void writeStrings(Map<String, String> map, String outputPath) throws Exception {
+        File output = new File(outputPath);
+        output.createNewFile();
+        FileWriter writer = new FileWriter(output);
+        try {
+            writer.write(getCopyRight());
+            writer.write("\n");
+            for (Entry<String, String> entry : map.entrySet()) {
+                String name = entry.getKey();
+                String value = entry.getValue();
+                writer.write(name + " = " + value + "\n");
+            }
+        } finally {
+            writer.close();
+        }
+    }
+
+    /**
+     * Very hacky parser for Android-understood-values.xml. It parses <string> </string>
+     * tags, and retrieve the name and the value associated.
+     *
+     * @param path to .xml containing android strings
+     * @return Map containing name and values.
+     */
+    @Nullable
+    private static Map<String, String> loadStrings(String path)
+            throws Exception {
+        // Use ordered map to minimize changes to strings.properties in git.
+        Map<String, String> toReturn = new LinkedHashMap<>();
+
+        File file = new File(path);
+        if (!file.exists()) {
+            System.err.println("The input file "+ path + " does not exist. Terminating.");
+            return toReturn;
+        }
+
+        DocumentBuilder documentBuilder = DocumentBuilderFactory
+                .newInstance().newDocumentBuilder();
+        Document document = documentBuilder.parse(file);
+        NodeList nodeList = document.getElementsByTagName("string");
+        for (int i = 0; i < nodeList.getLength(); i++) {
+            Node node = nodeList.item(i);
+            String name = node.getAttributes().getNamedItem("name").getNodeValue();
+
+            StringBuilder valueBuilder = new StringBuilder();
+            /**
+             * This is a very hacky way to bypass "ns1:g" tag in android's .xml.
+             * Ideally we'll read the tag from the parent and apply it here, but it being the
+             * deep node list I'm not currently sure how to parse it safely. Might need to look
+             * into IntelliJ PSI tree we have in Studio. But I didn't want to add unnecessary deps
+             * to LayoutLib.
+             *
+             * It also means resource namespaces are rendered useless after conversion.
+             */
+            for (int j = 0; j < node.getChildNodes().getLength(); j++) {
+                Node child = node.getChildNodes().item(j);
+                if ("ns1:g".equals(child.getNodeName())) {
+                    valueBuilder.append(child.getFirstChild().getNodeValue());
+                } else {
+                    valueBuilder.append(child.getNodeValue());
+                }
+            }
+            toReturn.put(name, valueBuilder.toString());
+        }
+        return toReturn;
+    }
+
+    private static String getCopyRight() {
+        return "\n" + "#\n" + "# Copyright (C) 2020 The Android Open Source Project\n" + "#\n" +
+                "# Licensed under the Apache License, Version 2.0 (the \"License\");\n" +
+                "# you may not use this file except in compliance with the License.\n" +
+                "# You may obtain a copy of the License at\n" + "#\n" +
+                "#      http://www.apache.org/licenses/LICENSE-2.0\n" + "#\n" +
+                "# Unless required by applicable law or agreed to in writing, software\n" +
+                "# distributed under the License is distributed on an \"AS IS\" BASIS,\n" +
+                "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" +
+                "# See the License for the specific language governing permissions and\n" +
+                "# limitations under the License.\n" + "#";
+    }
+}
diff --git a/validator/src/android/os/Build.java b/validator/src/android/os/Build.java
deleted file mode 100644
index 971f466..0000000
--- a/validator/src/android/os/Build.java
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * 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
index 0312ca9..dc34e90 100644
--- a/validator/src/com/android/tools/idea/validator/LayoutValidator.java
+++ b/validator/src/com/android/tools/idea/validator/LayoutValidator.java
@@ -21,9 +21,11 @@
 import com.android.tools.idea.validator.ValidatorData.Type;
 import com.android.tools.idea.validator.accessibility.AccessibilityValidator;
 import com.android.tools.layoutlib.annotations.NotNull;
+import com.android.tools.layoutlib.annotations.Nullable;
 
 import android.view.View;
 
+import java.awt.image.BufferedImage;
 import java.util.EnumSet;
 
 /**
@@ -31,10 +33,12 @@
  */
 public class LayoutValidator {
 
-    private static final ValidatorData.Policy DEFAULT_POLICY = new Policy(
+    public static final ValidatorData.Policy DEFAULT_POLICY = new Policy(
             EnumSet.of(Type.ACCESSIBILITY, Type.RENDER),
             EnumSet.of(Level.ERROR, Level.WARNING));
 
+    private static ValidatorData.Policy sPolicy = DEFAULT_POLICY;
+
     /**
      * Validate the layout using the default policy.
      * Precondition: View must be attached to the window.
@@ -42,11 +46,19 @@
      * @return The validation results. If no issue is found it'll return empty result.
      */
     @NotNull
-    public static ValidatorResult validate(@NotNull View view) {
+    public static ValidatorResult validate(@NotNull View view, @Nullable BufferedImage image) {
         if (view.isAttachedToWindow()) {
-            return AccessibilityValidator.validateAccessibility(view, DEFAULT_POLICY.mLevels);
+            return AccessibilityValidator.validateAccessibility(view, image, sPolicy);
         }
         // TODO: Add non-a11y layout validation later.
         return new ValidatorResult.Builder().build();
     }
+
+    /**
+     * Update the policy with which to run the validation call.
+     * @param policy new policy.
+     */
+    public static void updatePolicy(@NotNull ValidatorData.Policy policy) {
+        sPolicy = policy;
+    }
 }
diff --git a/validator/src/com/android/tools/idea/validator/ValidatorData.java b/validator/src/com/android/tools/idea/validator/ValidatorData.java
index f2112a5..6d9d6b6 100644
--- a/validator/src/com/android/tools/idea/validator/ValidatorData.java
+++ b/validator/src/com/android/tools/idea/validator/ValidatorData.java
@@ -20,6 +20,9 @@
 import com.android.tools.layoutlib.annotations.Nullable;
 
 import java.util.EnumSet;
+import java.util.HashSet;
+
+import com.google.android.apps.common.testing.accessibility.framework.AccessibilityHierarchyCheck;
 
 /**
  * Data used for layout validation.
@@ -32,6 +35,7 @@
     public enum Type {
         ACCESSIBILITY,
         RENDER,
+        INTERNAL_ERROR
     }
 
     /**
@@ -41,15 +45,17 @@
         ERROR,
         WARNING,
         INFO,
-        VERBOSE
+        /** The test not ran or suppressed. */
+        VERBOSE,
     }
 
     /**
      * Determine what types and levels of validation to run.
      */
     public static class Policy {
-        @NotNull final EnumSet<Type> mTypes;
-        @NotNull final EnumSet<Level> mLevels;
+        @NotNull public final EnumSet<Type> mTypes;
+        @NotNull public final EnumSet<Level> mLevels;
+        @NotNull public final HashSet<AccessibilityHierarchyCheck> mChecks = new HashSet();
 
         public Policy(@NotNull EnumSet<Type> types, @NotNull EnumSet<Level> levels) {
             mTypes = types;
@@ -71,24 +77,90 @@
     /**
      * 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 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;
+        @NotNull
+        public final String mSourceClass;
+        @Nullable
+        public final String mHelpfulUrl;
 
-        public Issue(
+        private Issue(
                 @NotNull Type type,
                 @NotNull String msg,
                 @NotNull Level level,
                 @Nullable Long srcId,
-                @Nullable Fix fix) {
+                @Nullable Fix fix,
+                @NotNull String sourceClass,
+                @Nullable String helpfulUrl) {
             mType = type;
             mMsg = msg;
             mLevel = level;
             mSrcId = srcId;
             mFix = fix;
+            mSourceClass = sourceClass;
+            mHelpfulUrl = helpfulUrl;
+        }
+
+        public static class IssueBuilder {
+            private Type mType = Type.ACCESSIBILITY;
+            private String mMsg;
+            private Level mLevel;
+            private Long mSrcId;
+            private Fix mFix;
+            private String mSourceClass;
+            private String mHelpfulUrl;
+
+            public IssueBuilder setType(Type type) {
+                mType = type;
+                return this;
+            }
+
+            public IssueBuilder setMsg(String msg) {
+                mMsg = msg;
+                return this;
+            }
+
+            public IssueBuilder setLevel(Level level) {
+                mLevel = level;
+                return this;
+            }
+
+            public IssueBuilder setSrcId(Long srcId) {
+                mSrcId = srcId;
+                return this;
+            }
+
+            public IssueBuilder setFix(Fix fix) {
+                mFix = fix;
+                return this;
+            }
+
+            public IssueBuilder setSourceClass(String sourceClass) {
+                mSourceClass = sourceClass;
+                return this;
+            }
+
+            public IssueBuilder setHelpfulUrl(String url) {
+                mHelpfulUrl = url;
+                return this;
+            }
+
+            public Issue build() {
+                assert(mType != null);
+                assert(mMsg != null);
+                assert(mLevel != null);
+                assert(mSourceClass != null);
+                return new Issue(mType, mMsg, mLevel, mSrcId, mFix, mSourceClass, mHelpfulUrl);
+            }
         }
     }
 }
diff --git a/validator/src/com/android/tools/idea/validator/ValidatorResult.java b/validator/src/com/android/tools/idea/validator/ValidatorResult.java
index 79129bc..8cc5c3d 100644
--- a/validator/src/com/android/tools/idea/validator/ValidatorResult.java
+++ b/validator/src/com/android/tools/idea/validator/ValidatorResult.java
@@ -36,13 +36,15 @@
 
     @NotNull private final ImmutableBiMap<Long, View> mSrcMap;
     @NotNull private final ArrayList<Issue> mIssues;
+    @NotNull private final Metric mMetric;
 
     /**
      * Please use {@link Builder} for creating results.
      */
-    private ValidatorResult(BiMap<Long, View> srcMap, ArrayList<Issue> issues) {
+    private ValidatorResult(BiMap<Long, View> srcMap, ArrayList<Issue> issues, Metric metric) {
         mSrcMap = ImmutableBiMap.<Long, View>builder().putAll(srcMap).build();
         mIssues = issues;
+        mMetric = metric;
     }
 
     /**
@@ -59,6 +61,13 @@
         return mIssues;
     }
 
+    /**
+     * @return metric for validation.
+     */
+    public Metric getMetric() {
+        return mMetric;
+    }
+
     @Override
     public String toString() {
         StringBuilder builder = new StringBuilder()
@@ -81,10 +90,55 @@
     public static class Builder {
         @NotNull public final BiMap<Long, View> mSrcMap = HashBiMap.create();
         @NotNull public final ArrayList<Issue> mIssues = new ArrayList<>();
+        @NotNull public final Metric mMetric = new Metric();
 
         public ValidatorResult build() {
-            return new ValidatorResult(mSrcMap, mIssues);
+            return new ValidatorResult(mSrcMap, mIssues, mMetric);
+        }
+    }
+
+    /**
+     * Contains metric specific data.
+     */
+    public static class Metric {
+        /** Error message. If null no error was thrown. */
+        public String mErrorMessage = null;
+
+        /** Records how long validation took */
+        public long mElapsedMs = 0;
+
+        /** How many new memories (bytes) validator creates for images. */
+        public long mImageMemoryBytes = 0;
+
+        private long mStart;
+
+        private Metric() { }
+
+        public void startTimer() {
+            mStart = System.currentTimeMillis();
         }
 
+        public void endTimer() {
+            mElapsedMs = System.currentTimeMillis() - mStart;
+        }
+
+        @Override
+        public String toString() {
+            return "Validation result metric: { elapsed=" + mElapsedMs +
+                    "ms, image memory=" + readableBytes() + " }";
+        }
+
+        private String readableBytes() {
+            if (mImageMemoryBytes > 1000000000) {
+                return mImageMemoryBytes / 1000000000 + "gb";
+            }
+            else if (mImageMemoryBytes > 1000000) {
+                return mImageMemoryBytes / 1000000 + "mb";
+            }
+            else if (mImageMemoryBytes > 1000) {
+                return mImageMemoryBytes / 1000 + "kb";
+            }
+            return mImageMemoryBytes + "bytes";
+        }
     }
 }
diff --git a/validator/src/com/android/tools/idea/validator/accessibility/AccessibilityValidator.java b/validator/src/com/android/tools/idea/validator/accessibility/AccessibilityValidator.java
index 3f59ff9..a2ec2c4 100644
--- a/validator/src/com/android/tools/idea/validator/accessibility/AccessibilityValidator.java
+++ b/validator/src/com/android/tools/idea/validator/accessibility/AccessibilityValidator.java
@@ -18,17 +18,20 @@
 
 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.Issue.IssueBuilder;
 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.idea.validator.ValidatorResult.Metric;
 import com.android.tools.layoutlib.annotations.NotNull;
 import com.android.tools.layoutlib.annotations.Nullable;
 
 import android.view.View;
 
+import java.awt.image.BufferedImage;
 import java.util.ArrayList;
 import java.util.EnumSet;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.ResourceBundle;
@@ -38,6 +41,7 @@
 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.Parameters;
 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;
@@ -66,17 +70,29 @@
     /**
      * Run Accessibility specific validation test and receive results.
      * @param view the root view
-     * @param filter list of levels to allow
+     * @param image the output image of the view. Null if not available.
+     * @param policy e.g: 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();
+            @Nullable BufferedImage image,
+            @NotNull ValidatorData.Policy policy) {
 
-        List<AccessibilityHierarchyCheckResult> results = getHierarchyCheckResults(view,
-                builder.mSrcMap);
+        EnumSet<Level> filter = policy.mLevels;
+        ValidatorResult.Builder builder = new ValidatorResult.Builder();
+        builder.mMetric.startTimer();
+        if (!policy.mTypes.contains(Type.ACCESSIBILITY)) {
+            return builder.build();
+        }
+
+        List<AccessibilityHierarchyCheckResult> results = getHierarchyCheckResults(
+                builder.mMetric,
+                view,
+                builder.mSrcMap,
+                image,
+                policy.mChecks);
 
         for (AccessibilityHierarchyCheckResult result : results) {
             ValidatorData.Level level = convertLevel(result.getType());
@@ -84,19 +100,32 @@
                 continue;
             }
 
-            ValidatorData.Fix fix = generateFix(result);
-            Long srcId = null;
-            if (result.getElement() != null) {
-                srcId = result.getElement().getCondensedUniqueId();
+            try {
+                IssueBuilder issueBuilder = new IssueBuilder()
+                        .setMsg(result.getMessage(Locale.ENGLISH).toString())
+                        .setLevel(level)
+                        .setFix(generateFix(result))
+                        .setSourceClass(result.getSourceCheckClass().getSimpleName());
+                if (result.getElement() != null) {
+                    issueBuilder.setSrcId(result.getElement().getCondensedUniqueId());
+                }
+                AccessibilityHierarchyCheck subclass = AccessibilityCheckPreset
+                        .getHierarchyCheckForClass(result
+                                .getSourceCheckClass()
+                                .asSubclass(AccessibilityHierarchyCheck.class));
+                if (subclass != null) {
+                    issueBuilder.setHelpfulUrl(subclass.getHelpUrl());
+                }
+                builder.mIssues.add(issueBuilder.build());
+            } catch (Exception e) {
+                builder.mIssues.add(new IssueBuilder()
+                        .setType(Type.INTERNAL_ERROR)
+                        .setMsg(e.getMessage())
+                        .setLevel(Level.ERROR)
+                        .setSourceClass("AccessibilityValidator").build());
             }
-            Issue issue = new Issue(
-                    Type.ACCESSIBILITY,
-                    result.getMessage(Locale.ENGLISH).toString(),
-                    level,
-                    srcId,
-                    fix);
-            builder.mIssues.add(issue);
         }
+        builder.mMetric.endTimer();
         return builder.build();
     }
 
@@ -125,15 +154,31 @@
 
     @NotNull
     private static List<AccessibilityHierarchyCheckResult> getHierarchyCheckResults(
+            @NotNull Metric metric,
             @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();
+            @NotNull BiMap<Long, View> originMap,
+            @Nullable BufferedImage image,
+            HashSet<AccessibilityHierarchyCheck> policyChecks) {
+
+        @NotNull Set<AccessibilityHierarchyCheck> checks = policyChecks.isEmpty()
+                ? AccessibilityCheckPreset
+                        .getAccessibilityHierarchyChecksForPreset(AccessibilityCheckPreset.LATEST)
+                : policyChecks;
+
+        @NotNull AccessibilityHierarchyAndroid hierarchy = AccessibilityHierarchyAndroid
+                .newBuilder(view)
+                .setViewOriginMap(originMap)
+                .build();
         ArrayList<AccessibilityHierarchyCheckResult> a11yResults = new ArrayList();
 
+        Parameters parameters = null;
+        if (image != null) {
+            parameters = new Parameters();
+            parameters.putScreenCapture(new AtfBufferedImage(image, metric));
+        }
+
         for (AccessibilityHierarchyCheck check : checks) {
-            a11yResults.addAll(check.runCheckOnHierarchy(hierarchy));
+            a11yResults.addAll(check.runCheckOnHierarchy(hierarchy, null, parameters));
         }
 
         return a11yResults;
diff --git a/validator/src/com/android/tools/idea/validator/accessibility/AtfBufferedImage.java b/validator/src/com/android/tools/idea/validator/accessibility/AtfBufferedImage.java
new file mode 100644
index 0000000..59d20a8
--- /dev/null
+++ b/validator/src/com/android/tools/idea/validator/accessibility/AtfBufferedImage.java
@@ -0,0 +1,98 @@
+/*
+ * 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.ValidatorResult.Metric;
+import com.android.tools.layoutlib.annotations.NotNull;
+
+import java.awt.image.BufferedImage;
+import java.awt.image.DataBufferInt;
+import java.awt.image.WritableRaster;
+
+import com.google.android.apps.common.testing.accessibility.framework.utils.contrast.Image;
+
+import static java.awt.image.BufferedImage.TYPE_INT_ARGB;
+
+/**
+ * Image implementation to be used in Accessibility Test Framework.
+ */
+public class AtfBufferedImage implements Image {
+
+    // The source buffered image, expected to contain the full screen rendered image of the layout.
+    @NotNull private final BufferedImage mBufferedImage;
+    // Metrics to be returned
+    @NotNull private final Metric mMetric;
+
+    private final int mLeft;
+    private final int mTop;
+    private final int mWidth;
+    private final int mHeight;
+
+    AtfBufferedImage(@NotNull BufferedImage image, @NotNull Metric metric) {
+        assert(image.getType() == TYPE_INT_ARGB);
+        mBufferedImage = image;
+        mMetric = metric;
+        mWidth = mBufferedImage.getWidth();
+        mHeight = mBufferedImage.getHeight();
+        mLeft = 0;
+        mTop = 0;
+    }
+
+    private AtfBufferedImage(
+            @NotNull BufferedImage image,
+            @NotNull Metric metric,
+            int left,
+            int top,
+            int width,
+            int height) {
+        mBufferedImage = image;
+        mMetric = metric;
+        mLeft = left;
+        mTop = top;
+        mWidth = width;
+        mHeight = height;
+    }
+
+    @Override
+    public int getHeight() {
+        return mHeight;
+    }
+
+    @Override
+    public int getWidth() {
+        return mWidth;
+    }
+
+    @Override
+    @NotNull
+    public Image crop(int left, int top, int width, int height) {
+        return new AtfBufferedImage(mBufferedImage, mMetric, left, top, width, height);
+    }
+
+    @Override
+    @NotNull
+    public int[] getPixels() {
+        // ATF unfortunately writes in-place on returned int[] for color analysis.
+        // It must return copied list otherwise it won't work.
+        BufferedImage cropped = mBufferedImage.getSubimage(mLeft, mTop, mWidth, mHeight);
+        WritableRaster raster = cropped.copyData(
+                cropped.getRaster().createCompatibleWritableRaster());
+        int[] toReturn = ((DataBufferInt) raster.getDataBuffer()).getData();
+        mMetric.mImageMemoryBytes += toReturn.length * 4;
+        return toReturn;
+    }
+}
diff --git a/validator/validator.iml b/validator/validator.iml
index e75d99a..f580aa3 100644
--- a/validator/validator.iml
+++ b/validator/validator.iml
@@ -41,14 +41,5 @@
         <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