aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Android.bp2
-rw-r--r--bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java19
-rw-r--r--bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test_switch_text_contrast.xml34
-rw-r--r--bridge/tests/src/com/android/tools/idea/validator/AccessibilityValidatorTests.java25
-rw-r--r--bridge/tests/src/com/android/tools/idea/validator/LayoutValidatorTests.java36
-rw-r--r--validator/resources/strings.properties4
-rw-r--r--validator/src/com/android/tools/idea/validator/AtfBufferedImage.java110
-rw-r--r--validator/src/com/android/tools/idea/validator/LayoutValidator.java57
-rw-r--r--validator/src/com/android/tools/idea/validator/ValidatorResult.java23
-rw-r--r--validator/src/com/android/tools/idea/validator/ValidatorUtil.java26
10 files changed, 295 insertions, 41 deletions
diff --git a/Android.bp b/Android.bp
index dd19d3777e..1609dbb41b 100644
--- a/Android.bp
+++ b/Android.bp
@@ -25,7 +25,7 @@ java_genrule_host {
tools: ["layoutlib_create"],
out: ["temp_layoutlib.jar"],
srcs: [
- ":atf-prebuilt-362209456{.jar}",
+ ":atf-prebuilt-369258897{.jar}",
":core-icu4j{.jar}",
":core-libart{.jar}",
":framework-all{.jar}",
diff --git a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index 968fcde593..77b9e8b418 100644
--- a/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -493,6 +493,8 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
HardwareConfig hardwareConfig = params.getHardwareConfig();
Result renderResult = SUCCESS.createResult();
+ float scaleX = 1.0f;
+ float scaleY = 1.0f;
if (onlyMeasure) {
// delete the canvas and image to reset them on the next full rendering
mImage = null;
@@ -529,11 +531,10 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
}
if (enableImageResizing) {
- mRenderer.setScale(mImage.getWidth() * 1.0f / mMeasuredScreenWidth,
- mImage.getHeight() * 1.0f / mMeasuredScreenHeight);
- } else {
- mRenderer.setScale(1.0f, 1.0f);
+ scaleX = mImage.getWidth() * 1.0f / mMeasuredScreenWidth;
+ scaleY = mImage.getHeight() * 1.0f / mMeasuredScreenHeight;
}
+ mRenderer.setScale(scaleX, scaleY);
if (mImageReader == null) {
mImageReader = ImageReader.newInstance(mImage.getWidth(), mImage.getHeight(), PixelFormat.RGBA_8888, 1);
@@ -600,11 +601,17 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
if (enableOptimization) {
ValidatorHierarchy hierarchy = LayoutValidator.buildHierarchy(
- ((View) getViewInfos().get(0).getViewObject()), imageToPass);
+ ((View) getViewInfos().get(0).getViewObject()),
+ imageToPass,
+ scaleX,
+ scaleY);
setValidatorHierarchy(hierarchy);
} else {
ValidatorResult validatorResult = LayoutValidator.validate(
- ((View) getViewInfos().get(0).getViewObject()), imageToPass);
+ ((View) getViewInfos().get(0).getViewObject()),
+ imageToPass,
+ scaleX,
+ scaleY);
setValidatorResult(validatorResult);
}
}
diff --git a/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test_switch_text_contrast.xml b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test_switch_text_contrast.xml
new file mode 100644
index 0000000000..db408f1b3b
--- /dev/null
+++ b/bridge/tests/res/testApp/MyApplication/src/main/res/layout/a11y_test_switch_text_contrast.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 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"
+ xmlns:tools="http://schemas.android.com/tools"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="#FFFFFFFF">
+ <!-- Low contrast, with slightly transparent text -->
+ <Switch
+ android:text="Switch"
+ android:textColor="#3000FFFF"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minHeight="48dp"
+ android:id="@+id/switch1"
+ tools:layout_editor_absoluteY="191dp"
+ tools:layout_editor_absoluteX="104dp" />
+</LinearLayout> \ No newline at end of file
diff --git a/bridge/tests/src/com/android/tools/idea/validator/AccessibilityValidatorTests.java b/bridge/tests/src/com/android/tools/idea/validator/AccessibilityValidatorTests.java
index dc3c4443c2..1359f293fe 100644
--- a/bridge/tests/src/com/android/tools/idea/validator/AccessibilityValidatorTests.java
+++ b/bridge/tests/src/com/android/tools/idea/validator/AccessibilityValidatorTests.java
@@ -110,7 +110,7 @@ public class AccessibilityValidatorTests extends RenderTestBase {
ExpectedLevels expectedLevels = new ExpectedLevels();
expectedLevels.expectedVerboses = 3;
expectedLevels.expectedWarnings = 1;
- expectedLevels.expectedFixes = 1;
+ expectedLevels.expectedFixes = 0;
expectedLevels.check(redundant);
});
}
@@ -187,6 +187,28 @@ public class AccessibilityValidatorTests extends RenderTestBase {
}
@Test
+ public void testSwitchTextContrastCheck() throws Exception {
+ render("a11y_test_switch_text_contrast.xml", session -> {
+ ValidatorResult result = getRenderResult(session);
+ List<Issue> textContrast = filter(result.getIssues(), "TextContrastCheck");
+
+ // ATF doesn't count alpha values in a Switch unless image is passed and the character
+ // locations are available.
+ ExpectedLevels expectedLevels = new ExpectedLevels();
+ expectedLevels.expectedErrors = 0;
+ expectedLevels.expectedWarnings = 1; // True only if character locations are available.
+ expectedLevels.expectedVerboses = 2;
+ expectedLevels.expectedFixes = 1;
+ 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);
@@ -339,6 +361,7 @@ public class AccessibilityValidatorTests extends RenderTestBase {
LayoutValidator.updatePolicy(new Policy(
EnumSet.of(Type.ACCESSIBILITY, Type.RENDER),
EnumSet.of(Level.ERROR, Level.WARNING, Level.INFO, Level.VERBOSE)));
+ LayoutValidator.setObtainCharacterLocations(true);
LayoutPullParser parser = createParserFromPath(fileName);
layoutLibCallback.initResources();
diff --git a/bridge/tests/src/com/android/tools/idea/validator/LayoutValidatorTests.java b/bridge/tests/src/com/android/tools/idea/validator/LayoutValidatorTests.java
index cf2770e618..659beede73 100644
--- a/bridge/tests/src/com/android/tools/idea/validator/LayoutValidatorTests.java
+++ b/bridge/tests/src/com/android/tools/idea/validator/LayoutValidatorTests.java
@@ -41,10 +41,24 @@ import com.google.android.apps.common.testing.accessibility.framework.Accessibil
import com.google.android.apps.common.testing.accessibility.framework.AccessibilityHierarchyCheck;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class LayoutValidatorTests extends RenderTestBase {
+ private static final float SCALE_X_FOR_NEXUS_5 = 1.0f;
+ private static final float SCALE_Y_FOR_NEXUS_5 = 1.0f;
+
+ @Test
+ public void testEnsureDebuggingOff() {
+ assertFalse(LayoutValidator.shouldSaveCroppedImages());
+ }
+
+ @Test
+ public void testEnsureObtainCharacterLocation() {
+ assertFalse(LayoutValidator.obtainCharacterLocations());
+ }
+
@Test
public void testRenderAndVerify() throws Exception {
LayoutPullParser parser = createParserFromPath("a11y_test1.xml");
@@ -65,8 +79,11 @@ public class LayoutValidatorTests extends RenderTestBase {
@Test
public void testValidation() throws Exception {
render(sBridge, generateParams(), -1, session -> {
- ValidatorResult result = LayoutValidator
- .validate(((View) session.getRootViews().get(0).getViewObject()), null);
+ ValidatorResult result = LayoutValidator.validate(
+ ((View) session.getRootViews().get(0).getViewObject()),
+ null,
+ SCALE_X_FOR_NEXUS_5,
+ SCALE_Y_FOR_NEXUS_5);
assertEquals(30, result.getIssues().size());
ArrayList<Issue> errorIssues = new ArrayList<>();
for (Issue issue : result.getIssues()) {
@@ -124,7 +141,10 @@ public class LayoutValidatorTests extends RenderTestBase {
render(sBridge, generateParams(), -1, session -> {
ValidatorResult result = LayoutValidator.validate(
- ((View) session.getRootViews().get(0).getViewObject()), null);
+ ((View) session.getRootViews().get(0).getViewObject()),
+ null,
+ SCALE_X_FOR_NEXUS_5,
+ SCALE_Y_FOR_NEXUS_5);
assertEquals(1, result.getIssues().size());
assertEquals("Hierarchy is not built yet.",
@@ -145,7 +165,10 @@ public class LayoutValidatorTests extends RenderTestBase {
render(sBridge, generateParams(), -1, session -> {
ValidatorResult result = LayoutValidator.validate(
- ((View) session.getRootViews().get(0).getViewObject()), null);
+ ((View) session.getRootViews().get(0).getViewObject()),
+ null,
+ SCALE_X_FOR_NEXUS_5,
+ SCALE_Y_FOR_NEXUS_5);
assertEquals(27, result.getIssues().size());
result.getIssues().forEach(issue ->assertEquals(Level.VERBOSE, issue.mLevel));
});
@@ -172,7 +195,10 @@ public class LayoutValidatorTests extends RenderTestBase {
render(sBridge, generateParams(), -1, session -> {
ValidatorResult result = LayoutValidator.validate(
- ((View) session.getRootViews().get(0).getViewObject()), null);
+ ((View) session.getRootViews().get(0).getViewObject()),
+ null,
+ SCALE_X_FOR_NEXUS_5,
+ SCALE_Y_FOR_NEXUS_5);
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 " +
diff --git a/validator/resources/strings.properties b/validator/resources/strings.properties
index 0e76740d35..7b324b94ca 100644
--- a/validator/resources/strings.properties
+++ b/validator/resources/strings.properties
@@ -82,8 +82,11 @@ result_message_background_must_be_opaque = This items\'s background color is not
result_message_addendum_opacity_description = Its actual opacity is %1$.2f%%.
result_message_brief_text_contrast_not_sufficient = Consider increasing this item\'s text foreground to background contrast ratio.
result_message_textview_contrast_not_sufficient = The item\'s text contrast ratio is %1$.2f. This ratio is based on a text color of <tt>#%2$06X</tt> and background color of <tt>#%3$06X</tt>. Consider increasing this item\'s text contrast ratio to %4$.2f or greater.
+result_message_customized_textview_contrast_not_sufficient = The item\'s text contrast ratio is %1$.2f. This ratio is based on a text color of <tt>#%2$06X</tt> and background color of <tt>#%3$06X</tt>. Consider using colors that result in a contrast ratio greater than the modified ratio of %4$.2f.
result_message_textview_heuristic_contrast_not_sufficient = The item\'s text contrast ratio is %1$.2f. This ratio is based on an estimated foreground color of <tt>#%2$06X</tt> and an estimated background color of <tt>#%3$06X</tt>. Consider using colors that result in a contrast ratio greater than %4$.2f for small text, or %5$.2f for large text.
+result_message_textview_heuristic_contrast_not_sufficient_when_text_size_available = The item\'s text contrast ratio is %1$.2f. This ratio is based on an estimated foreground color of <tt>#%2$06X</tt> and an estimated background color of <tt>#%3$06X</tt>. Consider increasing this item\'s text contrast ratio to %4$.2f or greater.
result_message_textview_heuristic_contrast_not_sufficient_confirmed = The item\'s text contrast ratio is %1$.2f. This ratio is based on the provided foreground color of <tt>#%2$06X</tt> and provided background color of <tt>#%3$06X</tt>. Consider using colors that result in a contrast ratio greater than %4$.2f for small text, or %5$.2f for large text.
+result_message_textview_heuristic_contrast_not_sufficient_when_text_size_available_confirmed = The item\'s text contrast ratio is %1$.2f. This ratio is based on the provided foreground color of <tt>#%2$06X</tt> and provided background color of <tt>#%3$06X</tt>. Consider increasing this item\'s text contrast ratio to %4$.2f or greater.
result_message_textview_heuristic_customized_contrast_not_sufficient = The item\'s text contrast ratio is %1$.2f. This ratio is based on an estimated foreground color of <tt>#%2$06X</tt> and an estimated background color of <tt>#%3$06X</tt>. Consider increasing this item\'s text contrast ratio to the modified ratio of %4$.2f or greater.
result_message_textview_heuristic_customized_contrast_not_sufficient_confirmed = The item\'s text contrast ratio is %1$.2f. This ratio is based on the provided foreground color of <tt>#%2$06X</tt> and provided background color of <tt>#%3$06X</tt>. Consider increasing this item\'s text contrast ratio to the modified ratio of %4$.2f or greater.
result_message_contrast_sufficient_confirmed = This item\'s foreground and background colors meet the suggested contrast ratio.
@@ -142,6 +145,7 @@ result_message_has_unexposed_items = This screen may have items that are not exp
result_message_is_unexposed_item_screen_region = The region with on-screen location <tt>%1$s</tt> contains at least one item that is not exposed to accessibility services.
check_title_item_exposed = Exposed items
result_message_brief_is_unexposed_item_screen_region = Consider exposing items in this region to accessibility services.
+check_title_text_size = Text Size
question_message_screen_has_unexposed_items = Does this screen contain important items that are not outlined?
question_message_identify_unexposed_items = Select regions of the screen with unidentified items.
suggestion_remove_view_attribute = Remove this item\'s <tt>%1$s</tt>.
diff --git a/validator/src/com/android/tools/idea/validator/AtfBufferedImage.java b/validator/src/com/android/tools/idea/validator/AtfBufferedImage.java
index f4d68f6f82..36c9170b77 100644
--- a/validator/src/com/android/tools/idea/validator/AtfBufferedImage.java
+++ b/validator/src/com/android/tools/idea/validator/AtfBufferedImage.java
@@ -16,14 +16,20 @@
package com.android.tools.idea.validator;
+import com.android.tools.idea.validator.ValidatorResult.ImageSize;
import com.android.tools.idea.validator.ValidatorResult.Metric;
import com.android.tools.layoutlib.annotations.NotNull;
+import android.annotation.NonNull;
+
import java.awt.image.BufferedImage;
import java.awt.image.DataBufferInt;
import java.awt.image.WritableRaster;
+import java.io.File;
+import java.io.IOException;
import com.google.android.apps.common.testing.accessibility.framework.utils.contrast.Image;
+import javax.imageio.ImageIO;
import static java.awt.image.BufferedImage.TYPE_INT_ARGB;
@@ -33,23 +39,42 @@ import static java.awt.image.BufferedImage.TYPE_INT_ARGB;
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;
+ @NotNull private final BufferedImage mImage;
// Metrics to be returned
@NotNull private final Metric mMetric;
+ // Points in before scaled coord
private final int mLeft;
private final int mTop;
private final int mWidth;
private final int mHeight;
- AtfBufferedImage(@NotNull BufferedImage image, @NotNull Metric metric) {
+ // Scale factors in case layoutlib scaled the screen.
+ private final float mScaleX;
+ private final float mScaleY;
+
+ AtfBufferedImage(
+ @NotNull BufferedImage image,
+ @NotNull Metric metric,
+ float scaleX,
+ float scaleY) {
+ // Without unscaling, atf does not recognize bounds that goes over the scaled image.
+ // E.g. if pxl4 is scaled to 1k x 2k (originally 2k x 4k), then atf could request for
+ // bounds at x:1.5k y:0, then without unscaling the call would fail.
+ this(image,
+ metric,
+ 0,
+ 0,
+ (int) (image.getWidth() * 1.0f / scaleX),
+ (int) (image.getHeight() * 1.0f / scaleY),
+ scaleX,
+ scaleY);
assert(image.getType() == TYPE_INT_ARGB);
- mBufferedImage = image;
- mMetric = metric;
- mWidth = mBufferedImage.getWidth();
- mHeight = mBufferedImage.getHeight();
- mLeft = 0;
- mTop = 0;
+
+ // FOR DEBUGGING ONLY
+ if (LayoutValidator.shouldSaveCroppedImages()) {
+ saveImage(image);
+ }
}
private AtfBufferedImage(
@@ -58,13 +83,17 @@ public class AtfBufferedImage implements Image {
int left,
int top,
int width,
- int height) {
- mBufferedImage = image;
+ int height,
+ float scaleX,
+ float scaleY) {
+ mImage = image;
mMetric = metric;
mLeft = left;
mTop = top;
mWidth = width;
mHeight = height;
+ mScaleX = scaleX;
+ mScaleY = scaleY;
}
@Override
@@ -80,19 +109,68 @@ public class AtfBufferedImage implements Image {
@Override
@NotNull
public Image crop(int left, int top, int width, int height) {
- return new AtfBufferedImage(mBufferedImage, mMetric, left, top, width, height);
+ return new AtfBufferedImage(mImage, mMetric, left, top, width, height, mScaleX, mScaleY);
}
+ /**
+ * @return the region that matches the scaled buffered image. The returned image
+ * will not have the width same as {@link #getWidth()} but rather width * mScaleX.
+ */
@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 scaledLeft = (int)(mLeft * mScaleX);
+ int scaledTop = (int)(mTop * mScaleY);
+ int scaledWidth = (int)(mWidth * mScaleX);
+ int scaledHeight = (int)(mHeight * mScaleY);
+
+ BufferedImage cropped = mImage.getSubimage(
+ scaledLeft, scaledTop, scaledWidth, scaledHeight);
+ WritableRaster raster =
+ cropped.copyData(cropped.getRaster().createCompatibleWritableRaster());
int[] toReturn = ((DataBufferInt) raster.getDataBuffer()).getData();
mMetric.mImageMemoryBytes += toReturn.length * 4;
+
+ if (LayoutValidator.shouldSaveCroppedImages()) {
+ saveImage(cropped);
+ }
+
return toReturn;
}
+
+ // FOR DEBUGGING ONLY
+ private static int SAVE_IMAGE_COUNTER = 0;
+ private void saveImage(BufferedImage image) {
+ try {
+ String name = SAVE_IMAGE_COUNTER + "_img_for_atf_LxT:WxH_" +
+ mLeft + "x" + mTop + ":" +
+ mWidth + "x" + mHeight;
+
+ mMetric.mImageSizes.add(new ImageSize(mLeft, mTop, mWidth, mHeight));
+
+ File output = new File(getDebugDir(), name);
+ if (output.exists()) {
+ output.delete();
+ }
+ ImageIO.write(image, "PNG", output);
+ SAVE_IMAGE_COUNTER++;
+ } catch (IOException ioe) {
+ mMetric.mErrorMessage = ioe.getMessage();
+ }
+ }
+
+ @NonNull
+ private File getDebugDir() {
+ File failureDir;
+ String failureDirString = System.getProperty("debug.dir");
+ if (failureDirString != null) {
+ failureDir = new File(failureDirString);
+ } else {
+ String workingDirString = System.getProperty("user.dir");
+ failureDir = new File(workingDirString, "out/debugs");
+ }
+
+ failureDir.mkdirs();
+ return failureDir;
+ }
}
diff --git a/validator/src/com/android/tools/idea/validator/LayoutValidator.java b/validator/src/com/android/tools/idea/validator/LayoutValidator.java
index efc628debb..df5befcbbf 100644
--- a/validator/src/com/android/tools/idea/validator/LayoutValidator.java
+++ b/validator/src/com/android/tools/idea/validator/LayoutValidator.java
@@ -40,6 +40,10 @@ public class LayoutValidator {
private static boolean sPaused = false;
+ private static boolean sSaveCroppedImages = false;
+
+ private static boolean sObtainCharacterLocations = false;
+
/**
* @return true if validator is paused. False otherwise.
*/
@@ -56,6 +60,34 @@ public class LayoutValidator {
sPaused = paused;
}
+ public static boolean shouldSaveCroppedImages() {
+ return sSaveCroppedImages;
+ }
+
+ /**
+ * For Debugging purpose. Save all cropped images used by atf if enabled.
+ * @param save
+ */
+ public static void setSaveCroppedImages(boolean save) {
+ sSaveCroppedImages = save;
+ }
+
+ /**
+ * Indicates whether text character locations should be requested.
+ *
+ * @param obtainCharacterLocations true if text character locations should be requested.
+ */
+ public static void setObtainCharacterLocations(boolean obtainCharacterLocations) {
+ sObtainCharacterLocations = obtainCharacterLocations;
+ }
+
+ /**
+ * @return true if text character locations should be requested.
+ */
+ public static boolean obtainCharacterLocations() {
+ return sObtainCharacterLocations;
+ }
+
/**
* Validate the layout using the default policy.
* Precondition: View must be attached to the window.
@@ -63,9 +95,18 @@ public class LayoutValidator {
* @return The validation results. If no issue is found it'll return empty result.
*/
@NotNull
- public static ValidatorResult validate(@NotNull View view, @Nullable BufferedImage image) {
+ public static ValidatorResult validate(
+ @NotNull View view,
+ @Nullable BufferedImage image,
+ float scaleX,
+ float scaleY) {
if (!sPaused && view.isAttachedToWindow()) {
- ValidatorHierarchy hierarchy = ValidatorUtil.buildHierarchy(sPolicy, view, image);
+ ValidatorHierarchy hierarchy = ValidatorUtil.buildHierarchy(
+ sPolicy,
+ view,
+ image,
+ scaleX,
+ scaleY);
return ValidatorUtil.generateResults(sPolicy, hierarchy);
}
// TODO: Add non-a11y layout validation later.
@@ -80,9 +121,17 @@ public class LayoutValidator {
*/
@NotNull
public static ValidatorHierarchy buildHierarchy(
- @NotNull View view, @Nullable BufferedImage image) {
+ @NotNull View view,
+ @Nullable BufferedImage image,
+ float scaleX,
+ float scaleY) {
if (!sPaused && view.isAttachedToWindow()) {
- return ValidatorUtil.buildHierarchy(sPolicy, view, image);
+ return ValidatorUtil.buildHierarchy(
+ sPolicy,
+ view,
+ image,
+ scaleX,
+ scaleY);
}
return new ValidatorHierarchy();
}
diff --git a/validator/src/com/android/tools/idea/validator/ValidatorResult.java b/validator/src/com/android/tools/idea/validator/ValidatorResult.java
index 76035f7c75..8f82646af6 100644
--- a/validator/src/com/android/tools/idea/validator/ValidatorResult.java
+++ b/validator/src/com/android/tools/idea/validator/ValidatorResult.java
@@ -113,6 +113,9 @@ public class ValidatorResult {
/** How many new memories (bytes) validator creates for images. */
public long mImageMemoryBytes = 0;
+ /** Debugging purpose only. Use it with {@link LayoutValidator#shouldSaveCroppedImages()} */
+ public List<ImageSize> mImageSizes = new ArrayList<>();
+
private long mStart;
private Metric() { }
@@ -149,4 +152,24 @@ public class ValidatorResult {
return mImageMemoryBytes + "bytes";
}
}
+
+ public static class ImageSize {
+ private final int mLeft;
+ private final int mTop;
+ private final int mWidth;
+ private final int mHeight;
+
+ public ImageSize(int left, int top, int width, int height) {
+ mLeft = left;
+ mTop = top;
+ mWidth = width;
+ mHeight = height;
+ }
+
+ @Override
+ public String toString() {
+ return "ImageSize{" + "mLeft=" + mLeft + ", mTop=" + mTop + ", mWidth=" + mWidth +
+ ", mHeight=" + mHeight + '}';
+ }
+ }
}
diff --git a/validator/src/com/android/tools/idea/validator/ValidatorUtil.java b/validator/src/com/android/tools/idea/validator/ValidatorUtil.java
index 63bea1baba..bdd363f88f 100644
--- a/validator/src/com/android/tools/idea/validator/ValidatorUtil.java
+++ b/validator/src/com/android/tools/idea/validator/ValidatorUtil.java
@@ -28,8 +28,6 @@ import com.android.tools.idea.validator.hierarchy.CustomHierarchyHelper;
import com.android.tools.layoutlib.annotations.NotNull;
import com.android.tools.layoutlib.annotations.Nullable;
-import org.jsoup.Jsoup;
-
import android.view.View;
import java.awt.image.BufferedImage;
@@ -46,13 +44,11 @@ import java.util.stream.Collectors;
import com.google.android.apps.common.testing.accessibility.framework.AccessibilityCheck;
import com.google.android.apps.common.testing.accessibility.framework.AccessibilityCheckPreset;
-import com.google.android.apps.common.testing.accessibility.framework.AccessibilityCheckResult;
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.checks.EditableContentDescCheck;
-import com.google.android.apps.common.testing.accessibility.framework.checks.RedundantDescriptionCheck;
import com.google.android.apps.common.testing.accessibility.framework.checks.TextContrastCheck;
import com.google.android.apps.common.testing.accessibility.framework.checks.TouchTargetSizeCheck;
import com.google.android.apps.common.testing.accessibility.framework.strings.StringManager;
@@ -98,19 +94,22 @@ public class ValidatorUtil {
*/
private final static ImmutableSet<Class<? extends AccessibilityHierarchyCheck>>
sAllowedCheckResultClassSet4Fix = ImmutableSet.of(TextContrastCheck.class,
- TouchTargetSizeCheck.class, RedundantDescriptionCheck.class,
- EditableContentDescCheck.class);
+ TouchTargetSizeCheck.class, EditableContentDescCheck.class);
/**s
* @param policy policy to apply for the hierarchy
* @param view root view to build hierarchy from
* @param image screenshot image that matches the view
+ * @param scaleX scaling done via layoutlib in x coord
+ * @param scaleY scaling done via layoutlib in y coord
* @return The hierarchical data required for running the ATF checks.
*/
public static ValidatorHierarchy buildHierarchy(
@NotNull ValidatorData.Policy policy,
@NotNull View view,
- @Nullable BufferedImage image) {
+ @Nullable BufferedImage image,
+ float scaleX,
+ float scaleY) {
ValidatorHierarchy hierarchy = new ValidatorHierarchy();
if (!policy.mTypes.contains(Type.ACCESSIBILITY)) {
return hierarchy;
@@ -123,6 +122,7 @@ public class ValidatorUtil {
hierarchy.mView = AccessibilityHierarchyAndroid
.newBuilder(view)
.setViewOriginMap(builder.mSrcMap)
+ .setObtainCharacterLocations(LayoutValidator.obtainCharacterLocations())
.setCustomViewBuilder(new CustomViewBuilderAndroid() {
@Override
public Class<?> getClassByName(
@@ -146,7 +146,7 @@ public class ValidatorUtil {
if (image != null) {
parameters = new Parameters();
parameters.putScreenCapture(
- new AtfBufferedImage(image, builder.mMetric));
+ new AtfBufferedImage(image, builder.mMetric, scaleX, scaleY));
}
builder.mMetric.recordHierarchyCreationTime();
@@ -197,6 +197,9 @@ public class ValidatorUtil {
}
for (AccessibilityHierarchyCheckResult result : a11yResults) {
+ // TODO: b/183726816 replace this with
+ // AccessibilityCheckPreset.getHierarchyCheckForClassName(checkClassName)
+ // .getTitleMessage(Locale.ENGLISH)
String category = ValidatorUtil.getCheckClassCategory(result.getSourceCheckClass());
ValidatorData.Level level = ValidatorUtil.convertLevel(result.getType());
@@ -239,6 +242,13 @@ public class ValidatorUtil {
}
/**
+ * @return the list of internal errors in results. Useful for testing and debugging.
+ */
+ public static List<Issue> filterInternalErrors(List<ValidatorData.Issue> results) {
+ return filterByTypes(results, EnumSet.of(Type.INTERNAL_ERROR));
+ }
+
+ /**
* @return the list filtered by the level. Useful for testing and debugging.
*/
public static List<Issue> filter(List<ValidatorData.Issue> results, EnumSet<Level> errors) {