1704d59a9e57b28939ba5c709cf4b50d72aa072e6Christian Williamspackage org.robolectric.android; 255e6fdf6aef81359df48acc92714f89111b7613bErich Douglass 3e3260798aeb2a5a4440966a270f859847f25254aChristian Williamsimport android.view.View; 455e6fdf6aef81359df48acc92714f89111b7613bErich Douglassimport com.google.android.apps.common.testing.accessibility.framework.AccessibilityCheckPreset; 532f582faf0b5e6658a19046afb44d33f712d121ePhil Weaverimport com.google.android.apps.common.testing.accessibility.framework.AccessibilityCheckResult; 6510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaverimport com.google.android.apps.common.testing.accessibility.framework.AccessibilityCheckResult.AccessibilityCheckResultType; 755e6fdf6aef81359df48acc92714f89111b7613bErich Douglassimport com.google.android.apps.common.testing.accessibility.framework.AccessibilityCheckResultUtils; 855e6fdf6aef81359df48acc92714f89111b7613bErich Douglassimport com.google.android.apps.common.testing.accessibility.framework.AccessibilityViewCheckResult; 932f582faf0b5e6658a19046afb44d33f712d121ePhil Weaverimport com.google.android.apps.common.testing.accessibility.framework.DuplicateClickableBoundsViewCheck; 108c34621d8da4bc313229be97b4ef30cdeb0ad852Phil Weaverimport com.google.android.apps.common.testing.accessibility.framework.TouchTargetSizeViewCheck; 1132f582faf0b5e6658a19046afb44d33f712d121ePhil Weaverimport com.google.android.apps.common.testing.accessibility.framework.integrations.espresso.AccessibilityValidator; 12e3260798aeb2a5a4440966a270f859847f25254aChristian Williamsimport java.lang.annotation.Annotation; 1355e6fdf6aef81359df48acc92714f89111b7613bErich Douglassimport java.lang.reflect.Method; 14510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaverimport java.util.Collections; 1555e6fdf6aef81359df48acc92714f89111b7613bErich Douglassimport java.util.List; 16851f2a9519be23c73a9e2929128179b405e2e7a6Christian Williamsimport org.hamcrest.Matcher; 17851f2a9519be23c73a9e2929128179b405e2e7a6Christian Williamsimport org.hamcrest.Matchers; 18851f2a9519be23c73a9e2929128179b405e2e7a6Christian Williamsimport org.robolectric.annotation.AccessibilityChecks; 19851f2a9519be23c73a9e2929128179b405e2e7a6Christian Williamsimport org.robolectric.annotation.AccessibilityChecks.ForRobolectricVersion; 2055e6fdf6aef81359df48acc92714f89111b7613bErich Douglass 2155e6fdf6aef81359df48acc92714f89111b7613bErich Douglass/** 22510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * Utility class for checking Views for accessibility. 23510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * 24510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * This class is used by {@code ShadowView.checkedPerformClick} to check for accessibility problems. 25510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * There is some subtlety to checking a UI for accessibility when it hasn't been rendered. The 26510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * better initialized the View, the more accurate the checking will be. At a minimum, the view 27510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * should be attached to a proper view hierarchy similar to what's checked for in:q 28510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * {@code ShadowView.checkedPerformClick}. 2955e6fdf6aef81359df48acc92714f89111b7613bErich Douglass */ 3055e6fdf6aef81359df48acc92714f89111b7613bErich Douglasspublic class AccessibilityUtil { 3132f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver private static final String COMPAT_V4_CLASS_NAME = "android.support.v4.view.ViewCompat"; 3232f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver /* The validator that this class configures and uses to run the checks */ 3332f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver private static AccessibilityValidator validator; 3432f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver 3532f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver /* 3632f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver * Slightly hacky way to deal with the legacy of allowing the annotation to configure the 3732f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver * subset of checks to run from the annotation. {@code true} when a version set is 3832f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver * specified by setRunChecksForRobolectricVersion. 3932f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver */ 4032f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver private static boolean forVersionSet = false; 4132f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver 4232f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver /* Flag indicating if the support library's presence has been verified */ 4332f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver private static boolean v4SupportPresenceVerified = false; 4432f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver 45bd8b4b4b73ddcce4b22e5fd9213eeca1218f4756Christian Williams protected AccessibilityUtil() {} 4655e6fdf6aef81359df48acc92714f89111b7613bErich Douglass 4755e6fdf6aef81359df48acc92714f89111b7613bErich Douglass /** 48510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * Check a hierarchy of {@code View}s for accessibility. Only performs checks if (in decreasing 49510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * priority order) accessibility checking is enabled using an {@link AccessibilityChecks} 50510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * annotation, if the system property {@code robolectric.accessibility.enablechecks} is set to 51510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * {@code true}, or if the environment variable {@code robolectric.accessibility.enablechecks} 52510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * is set to {@code true}. 5332f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver * 5432f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver * @param view The {@code View} to examine 55510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * 56510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * @return A list of results from the check. If there are no results or checking is disabled, 57510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * the list is empty. 5832f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver */ 59510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver public static List<AccessibilityViewCheckResult> checkViewIfCheckingEnabled(View view) { 60510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver AccessibilityChecks classChecksAnnotation = getAnnotation(); 61510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver if (!isAccessibilityCheckingEnabled(classChecksAnnotation)) { 62510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver return Collections.emptyList(); 63510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver } 64510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver 65510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver return checkView(view); 6632f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver } 67510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver 68510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver /** 69510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * Check a hierarchy of {@code View}s for accessibility, based on currently set options. 70510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * 71510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * @param view The {@code View} to examine 72510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * 73510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * @return A list of results from the check. If there are no results, the list is empty. 74510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver */ 75510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver public static List<AccessibilityViewCheckResult> checkView(View view) { 76510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver return checkView(view, getAnnotation()); 77510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver } 78510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver 79510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver /** 80510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * Check a hierarchy of {@code View}s for accessibility. Only performs checks if (in decreasing 81510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * priority order) accessibility checking is enabled using an {@link AccessibilityChecks} 82510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * annotation, if the system property {@code robolectric.accessibility.enablechecks} is set to 83510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * {@code true}, or if the environment variable {@code robolectric.accessibility.enablechecks} 84510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * is set to {@code true}. 85510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * 86510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * Implicitly calls {code setThrowExceptionForErrors(false)} to disable exception throwing. This 87510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * method is deprecated, both because of this side effect and because the other methods offer 88510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * more control over execution. 89510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * 90510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * @param view The {@code View} to examine 91510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * 92510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * @return A list of results from the check. If there are no results or checking is disabled, 93510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * the list is empty. 94510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver */ 95510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver @Deprecated 96510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver public static boolean passesAccessibilityChecksIfEnabled(View view) { 97510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver setThrowExceptionForErrors(false); 98510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver List<AccessibilityViewCheckResult> results = checkViewIfCheckingEnabled(view); 99510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver List<AccessibilityViewCheckResult> errors = AccessibilityCheckResultUtils.getResultsForType( 100510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver results, AccessibilityCheckResultType.ERROR); 101510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver return (errors.size() == 0); 102510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver } 103510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver 10432f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver /** 10532f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver * Specify that a specific subset of accessibility checks be run. The subsets are specified based 10632f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver * on which Robolectric version particular checks were released with. By default, all checks are 10782049a7b7c53d5a208921940bda298535697d0b7Christian Williams * run {@link ForRobolectricVersion}. 10882049a7b7c53d5a208921940bda298535697d0b7Christian Williams * 10932f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver * If you call this method, the value you pass will take precedence over any value in any 11032f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver * annotations. 11132f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver * 11232f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver * @param forVersion The version of checks to run for. If {@code null}, throws away the current 11332f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver * value and falls back on the annotation or default. 11432f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver */ 11532f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver public static void setRunChecksForRobolectricVersion(ForRobolectricVersion forVersion) { 11632f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver initializeValidator(); 11732f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver if (forVersion != null) { 11832f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver validator.setCheckPreset(convertRoboVersionToA11yTestVersion(forVersion)); 11932f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver forVersionSet = true; 12032f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver } else { 12132f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver forVersionSet = false; 12232f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver } 12332f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver } 12432f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver 12532f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver /** 12632f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver * Specify that accessibility checks should be run for all views in the hierarchy whenever a 12732f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver * single view's accessibility is asserted. 12832f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver * 12932f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver * @param runChecksFromRootView {@code true} if all views in the hierarchy should be checked. 13032f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver */ 13132f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver public static void setRunChecksFromRootView(boolean runChecksFromRootView) { 13232f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver initializeValidator(); 13332f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver validator.setRunChecksFromRootView(runChecksFromRootView); 13432f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver } 13532f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver 13632f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver /** 13732f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver * Suppress all results that match the given matcher. Suppressed results will not be included 13832f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver * in any logs or cause any {@code Exception} to be thrown. This capability is useful if there 13932f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver * are known issues, but checks should still look for regressions. 14032f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver * 14132f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver * @param matcher A matcher to match a {@link AccessibilityViewCheckResult}. {@code null} 14232f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver * disables suppression and is the default. 14332f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver */ 14432f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver @SuppressWarnings("unchecked") // The generic passed to anyOf 14532f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver public static void setSuppressingResultMatcher( 14632f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver final Matcher<? super AccessibilityViewCheckResult> matcher) { 14732f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver initializeValidator(); 14832f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver /* Suppress all touch target results, since views all report size as 0x0 */ 14932f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver Matcher<AccessibilityCheckResult> touchTargetResultMatcher = 15032f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver AccessibilityCheckResultUtils.matchesChecks( 15132f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver Matchers.equalTo(TouchTargetSizeViewCheck.class)); 15232f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver Matcher<AccessibilityCheckResult> duplicateBoundsResultMatcher = 15332f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver AccessibilityCheckResultUtils.matchesChecks( 15432f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver Matchers.equalTo(DuplicateClickableBoundsViewCheck.class)); 15532f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver if (matcher == null) { 15632f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver validator.setSuppressingResultMatcher( 15732f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver Matchers.anyOf(touchTargetResultMatcher, duplicateBoundsResultMatcher)); 15832f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver } else { 15932f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver validator.setSuppressingResultMatcher( 16032f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver Matchers.anyOf(matcher, touchTargetResultMatcher, duplicateBoundsResultMatcher)); 16132f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver } 16232f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver } 16332f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver 16432f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver /** 16532f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver * Control whether or not to throw exceptions when accessibility errors are found. 16632f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver * 16732f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver * @param throwExceptionForErrors {@code true} to throw an {@code AccessibilityViewCheckException} 16832f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver * when there is at least one error result. Default: {@code true}. 16932f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver */ 17032f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver public static void setThrowExceptionForErrors(boolean throwExceptionForErrors) { 17132f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver initializeValidator(); 17232f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver validator.setThrowExceptionForErrors(throwExceptionForErrors); 17332f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver } 17432f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver 175510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver private static List<AccessibilityViewCheckResult> checkView(View view, 176510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver AccessibilityChecks classChecksAnnotation) { 177510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver /* 178510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * Accessibility Checking requires the v4 support library. If the support library isn't present, 179510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver * throw a descriptive exception now. 180510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver */ 181510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver if (!v4SupportPresenceVerified) { 182510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver try { 183510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver View.class.getClassLoader().loadClass(COMPAT_V4_CLASS_NAME); 184510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver } catch (ClassNotFoundException e) { 185510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver throw new RuntimeException( 186510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver "Accessibility Checking requires the Android support library (v4).\n" 187510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver + "Either include it in the project or disable accessibility checking."); 18832f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver } 189510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver v4SupportPresenceVerified = true; 190510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver } 19155e6fdf6aef81359df48acc92714f89111b7613bErich Douglass 192510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver initializeValidator(); 193510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver if (!forVersionSet) { 194510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver if (classChecksAnnotation != null) { 195510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver validator.setCheckPreset( 196510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver convertRoboVersionToA11yTestVersion(classChecksAnnotation.forRobolectricVersion())); 197510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver } else { 198510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver validator.setCheckPreset(AccessibilityCheckPreset.LATEST); 19932f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver } 20032f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver } 201510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver return validator.checkAndReturnResults(view); 202510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver } 203510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver 204510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver private static boolean isAccessibilityCheckingEnabled(AccessibilityChecks classChecksAnnotation) { 205510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver boolean checksEnabled = false; 206510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver 207510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver String checksEnabledString = System.getenv("robolectric.accessibility.enablechecks"); 208510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver if (checksEnabledString != null) { 209510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver checksEnabled = checksEnabledString.equals("true"); 210510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver } 211510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver 212510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver /* Allow test arg to enable checking (and override environment variables) */ 213510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver checksEnabledString = System.getProperty("robolectric.accessibility.enablechecks"); 214510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver if (checksEnabledString != null) { 215510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver checksEnabled = checksEnabledString.equals("true"); 216510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver } 217510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver 218510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver if (classChecksAnnotation != null) { 219510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver checksEnabled = classChecksAnnotation.enabled(); 220510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver } 221510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver 222510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver return checksEnabled; 223510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver } 224510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver 225510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver private static AccessibilityChecks getAnnotation() { 22632f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver AccessibilityChecks classChecksAnnotation = null; 227510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver StackTraceElement[] stack = new Throwable().fillInStackTrace().getStackTrace(); 22855e6fdf6aef81359df48acc92714f89111b7613bErich Douglass for (StackTraceElement element : stack) { 22955e6fdf6aef81359df48acc92714f89111b7613bErich Douglass /* Look for annotations on the method or the class */ 23055e6fdf6aef81359df48acc92714f89111b7613bErich Douglass Class<?> clazz; 23155e6fdf6aef81359df48acc92714f89111b7613bErich Douglass try { 23255e6fdf6aef81359df48acc92714f89111b7613bErich Douglass clazz = Class.forName(element.getClassName()); 23355e6fdf6aef81359df48acc92714f89111b7613bErich Douglass Method method; 23455e6fdf6aef81359df48acc92714f89111b7613bErich Douglass method = clazz.getMethod(element.getMethodName()); 23555e6fdf6aef81359df48acc92714f89111b7613bErich Douglass /* Assume the method is void, as that is the case for tests */ 23632f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver classChecksAnnotation = method.getAnnotation(AccessibilityChecks.class); 23755e6fdf6aef81359df48acc92714f89111b7613bErich Douglass if (classChecksAnnotation == null) { 23855e6fdf6aef81359df48acc92714f89111b7613bErich Douglass classChecksAnnotation = clazz.getAnnotation(AccessibilityChecks.class); 23955e6fdf6aef81359df48acc92714f89111b7613bErich Douglass } 240510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver /* Stop looking when we find an annotation */ 24155e6fdf6aef81359df48acc92714f89111b7613bErich Douglass if (classChecksAnnotation != null) { 24255e6fdf6aef81359df48acc92714f89111b7613bErich Douglass break; 24355e6fdf6aef81359df48acc92714f89111b7613bErich Douglass } 244e3260798aeb2a5a4440966a270f859847f25254aChristian Williams 24555e6fdf6aef81359df48acc92714f89111b7613bErich Douglass /* If we've crawled up the stack far enough to find the test, stop looking */ 246e3260798aeb2a5a4440966a270f859847f25254aChristian Williams for (Annotation annotation : clazz.getAnnotations()) { 2475cb217a0f521dc390fdaa3050889b03a7da4d1cfJonathan Gerrish if (annotation.annotationType().getName().equals("org.junit.Test")) { 248e3260798aeb2a5a4440966a270f859847f25254aChristian Williams break; 249e3260798aeb2a5a4440966a270f859847f25254aChristian Williams } 25055e6fdf6aef81359df48acc92714f89111b7613bErich Douglass } 25155e6fdf6aef81359df48acc92714f89111b7613bErich Douglass } 25255e6fdf6aef81359df48acc92714f89111b7613bErich Douglass /* 25355e6fdf6aef81359df48acc92714f89111b7613bErich Douglass * The reflective calls may throw exceptions if the stack trace elements 25455e6fdf6aef81359df48acc92714f89111b7613bErich Douglass * don't look like junit test methods. In that case we simply go on 25555e6fdf6aef81359df48acc92714f89111b7613bErich Douglass * to the next element 25655e6fdf6aef81359df48acc92714f89111b7613bErich Douglass */ 25777ae4054c6fd36bd2efa66068c63c7a4635a1593Erich Douglass catch (ClassNotFoundException | SecurityException | NoSuchMethodException e) {} 25855e6fdf6aef81359df48acc92714f89111b7613bErich Douglass } 259510eddc53293fa1ff6a672660e3c2eb904746d00Phil Weaver return classChecksAnnotation; 26032f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver } 26155e6fdf6aef81359df48acc92714f89111b7613bErich Douglass 26232f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver private static void initializeValidator() { 26332f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver if (validator == null) { 26432f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver validator = new AccessibilityValidator(); 26532f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver setSuppressingResultMatcher(null); 26655e6fdf6aef81359df48acc92714f89111b7613bErich Douglass } 26732f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver } 26855e6fdf6aef81359df48acc92714f89111b7613bErich Douglass 26932f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver private static AccessibilityCheckPreset convertRoboVersionToA11yTestVersion( 27032f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver ForRobolectricVersion robolectricVersion) { 27132f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver if (robolectricVersion == ForRobolectricVersion.LATEST) { 27232f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver return AccessibilityCheckPreset.LATEST; 27355e6fdf6aef81359df48acc92714f89111b7613bErich Douglass } 27432f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver AccessibilityCheckPreset preset = AccessibilityCheckPreset.VERSION_1_0_CHECKS; 27532f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver if (robolectricVersion.ordinal() >= ForRobolectricVersion.VERSION_3_1.ordinal()) { 27632f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver preset = AccessibilityCheckPreset.VERSION_2_0_CHECKS; 27732f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver } 27832f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver return preset; 27932f582faf0b5e6658a19046afb44d33f712d121ePhil Weaver } 28005a44e0f3250a52784027324d41be41858a67ef8Roger Hu} 281