diff options
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) { |