Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
281 views
in Technique[技术] by (71.8m points)

Android Custom Lint Rule Checks Not Visible On UI

I'm trying to implement a custom lint rule that checks xml files and reports an issue if some UI elements' width or height is less than a certain DP amount. It seems to work just fine if you perform ./gradlew lintDebug, but I can't see any results and/or suggestions on UI in Android Studio.

I am following these materials https://proandroiddev.com/implementing-your-first-android-lint-rule-6e572383b292, https://www.youtube.com/watch?v=jCmJWOkjbM0 as well as browsing the built-in lint rules sources.

@SuppressWarnings("UnstableApiUsage")
public class ElementSizeScanner extends ResourceXmlDetector implements XmlScanner {

    private static final Implementation IMPLEMENTATION = new Implementation(ElementSizeScanner.class, Scope.RESOURCE_FILE_SCOPE);
    public static final Issue TOO_SMALL_AREA_ISSUE = Issue.create(
            "TooSmallArea",
            "The dimension must be at least 44dp",
            "Using clickable elements which dimensions are smaller than 44dp may cause accessibility issues",
            Category.A11Y,
            7,
            Severity.ERROR,
            IMPLEMENTATION
    );

    private static final int MINIMAL_SIZE = 44;
    private static final List<String> LAYOUT_ELEMENTS = Arrays.asList(SdkConstants.TEXT_VIEW,
            SdkConstants.IMAGE_VIEW, SdkConstants.BUTTON, SdkConstants.FRAME_LAYOUT);

    private final Map<String, String> dimens = new HashMap<>();

    @Nullable
    @Override
    public Collection<String> getApplicableElements() {
        List<String> applicableElements = new ArrayList<>(LAYOUT_ELEMENTS);
        applicableElements.add(SdkConstants.TAG_DIMEN);
        return applicableElements;
    }

    @Override
    public boolean appliesTo(@NotNull ResourceFolderType folderType) {
        return folderType == ResourceFolderType.LAYOUT || folderType == ResourceFolderType.VALUES;
    }

    @Override
    public void visitElement(@NotNull XmlContext context, @NotNull Element element) {
        super.visitElement(context, element);
        if (context.getPhase() == 1) {
            if (element.getTagName().equals(SdkConstants.TAG_DIMEN)) {
                String name = element.getAttribute(SdkConstants.ATTR_NAME);
                String value = element.getFirstChild().getNodeValue();
                dimens.put(name, value);
            }
        } else if (!dimens.isEmpty()) {
            if (LAYOUT_ELEMENTS.contains(element.getTagName())) {
                DimensionChecker dimensionChecker = new DimensionChecker(MINIMAL_SIZE, context, dimens);
                String width = element.getAttribute(SdkConstants.ANDROID_NS_NAME_PREFIX + SdkConstants.ATTR_LAYOUT_WIDTH);
                String height = element.getAttribute(SdkConstants.ANDROID_NS_NAME_PREFIX + SdkConstants.ATTR_LAYOUT_HEIGHT);
                dimensionChecker.checkDimension(element, SdkConstants.ATTR_LAYOUT_WIDTH, width);
                dimensionChecker.checkDimension(element, SdkConstants.ATTR_LAYOUT_HEIGHT, height);
            }
        }
    }

    @Override
    public void afterCheckRootProject(@NotNull Context context) {
        super.afterCheckRootProject(context);
        // Phase 1 - collect dimen values
        // Phase 2 - check dimen values
        if (context.getPhase() == 1) {
            context.requestRepeat(this, Scope.RESOURCE_FILE_SCOPE);
        }
    }
}

@SuppressWarnings("UnstableApiUsage")
public class DimensionChecker {

    private final int minSize;
    private final XmlContext context;
    private final Map<String, String> dimens;

    public DimensionChecker(int minSize,
                            XmlContext context,
                            Map<String, String> dimens) {
        this.minSize = minSize;
        this.context = context;
        this.dimens = dimens;
    }

    public void checkDimension(Element element, String dimensionName, String dimension) {
        // some checks here

        double doubleValue;
        try {
            doubleValue = parseDimenValue(dimenValue);
        } catch (NumberFormatException e) {
            return;
        }

        if (doubleValue < minSize) {
            LintFix lintFix = LintFix.create()
                    .set(ANDROID_URI, dimensionName, minSize + SdkConstants.UNIT_DP)
                    .build();
            context.report(
                    ElementSizeScanner.TOO_SMALL_AREA_ISSUE,
                    element,
                    context.getValueLocation(element.getAttributeNodeNS(ANDROID_URI, dimensionName)),
                    "The area is too small to click",
                    lintFix
            );
        }
    }

    private double parseDimenValue(String value) throws NumberFormatException {
        // ...
    }
}

The rule is applied to the project with lintChecks project(path: ':rules')

What might I be missing here?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)
等待大神答复

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to WuJiGu Developer Q&A Community for programmer and developer-Open, Learning and Share
...