Java Code Examples for com.android.tools.lint.detector.api.XmlContext#getLocation()

The following examples show how to use com.android.tools.lint.detector.api.XmlContext#getLocation() . You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: MissingClassDetector.java    From javaide with GNU General Public License v3.0 6 votes vote down vote up
private static void checkInnerClass(XmlContext context, Element element, String pkg,
        Node classNameNode, String className) {
    if (pkg != null && className.indexOf('$') == -1 && className.indexOf('.', 1) > 0) {
        boolean haveUpperCase = false;
        for (int i = 0, n = pkg.length(); i < n; i++) {
            if (Character.isUpperCase(pkg.charAt(i))) {
                haveUpperCase = true;
                break;
            }
        }
        if (!haveUpperCase) {
            String fixed = className.charAt(0) + className.substring(1).replace('.','$');
            String message = "Use '$' instead of '.' for inner classes " +
                    "(or use only lowercase letters in package names); replace \"" +
                    className + "\" with \"" + fixed + "\"";
            Location location = context.getLocation(classNameNode);
            context.report(INNERCLASS, element, location, message);
        }
    }
}
 
Example 2
Source File: WebViewDetector.java    From javaide with GNU General Public License v3.0 6 votes vote down vote up
@Override
public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
    Node parentNode = element.getParentNode();
    if (parentNode != null && parentNode.getNodeType() == Node.ELEMENT_NODE) {
        Element parent = (Element)parentNode;
        Attr width = parent.getAttributeNodeNS(ANDROID_URI, ATTR_LAYOUT_WIDTH);
        Attr height = parent.getAttributeNodeNS(ANDROID_URI, ATTR_LAYOUT_HEIGHT);
        Attr attr = null;
        if (width != null && VALUE_WRAP_CONTENT.equals(width.getValue())) {
            attr = width;
        }
        if (height != null && VALUE_WRAP_CONTENT.equals(height.getValue())) {
            attr = height;
        }
        if (attr != null) {
            String message = String.format("Placing a `<WebView>` in a parent element that "
                    + "uses a `wrap_content %1$s` can lead to subtle bugs; use `match_parent` "
                    + "instead", attr.getLocalName());
            Location location = context.getLocation(element);
            Location secondary = context.getLocation(attr);
            secondary.setMessage("`wrap_content` here may not work well with WebView below");
            location.setSecondary(secondary);
            context.report(ISSUE, element, location, message);
        }
    }
}
 
Example 3
Source File: TypoDetector.java    From javaide with GNU General Public License v3.0 5 votes vote down vote up
/** Reports a repeated word */
private static void reportRepeatedWord(XmlContext context, Node node, String text,
        int lastWordBegin,
        int begin, int end) {
    String message = String.format(
            "Repeated word \"%1$s\" in message: possible typo",
            text.substring(begin, end));
    Location location = context.getLocation(node, lastWordBegin, end);
    context.report(ISSUE, node, location, message);
}
 
Example 4
Source File: TextFieldDetector.java    From javaide with GNU General Public License v3.0 5 votes vote down vote up
private static void reportMismatch(XmlContext context, Attr idNode, Node inputTypeNode,
        String message) {
    Location location;
    if (inputTypeNode != null) {
        location = context.getLocation(inputTypeNode);
        Location secondary = context.getLocation(idNode);
        secondary.setMessage("id defined here");
        location.setSecondary(secondary);
    } else {
        location = context.getLocation(idNode);
    }
    context.report(ISSUE, idNode.getOwnerElement(), location, message);
}
 
Example 5
Source File: ByteOrderMarkDetector.java    From javaide with GNU General Public License v3.0 5 votes vote down vote up
@Override
public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) {
    String name = attribute.getValue();
    for (int i = 0, n = name.length(); i < n; i++) {
        char c = name.charAt(i);
        if (c == '\uFEFF') {
            Location location = context.getLocation(attribute);
            String message = "Found byte-order-mark in the middle of a file";
            context.report(BOM, null, location, message);
            break;
        }
    }
}
 
Example 6
Source File: OverdrawDetector.java    From javaide with GNU General Public License v3.0 4 votes vote down vote up
@Override
public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) {
    // Ignore tools:background and any other custom attribute that isn't actually the
    // android View background attribute
    if (!ANDROID_URI.equals(attribute.getNamespaceURI())) {
        return;
    }

    // Only consider the root element's background
    Element documentElement = attribute.getOwnerDocument().getDocumentElement();
    if (documentElement == attribute.getOwnerElement()) {
        // If the drawable is a non-repeated pattern then the overdraw might be
        // intentional since the image isn't covering the whole screen
        String background = attribute.getValue();
        if (mValidDrawables != null && mValidDrawables.contains(background)) {
            return;
        }

        if (background.equals(TRANSPARENT_COLOR) || background.equals(NULL_RESOURCE)) {
            return;
        }

        if (background.startsWith("@android:drawable/")) { //$NON-NLS-1$
            // We haven't had a chance to study the builtin drawables the way we
            // check the project local ones in scanBitmap() and beforeCheckFile(),
            // but many of these are not bitmaps, so ignore these
            return;
        }

        String name = context.file.getName();
        if (name.contains("list_") || name.contains("_item")) { //$NON-NLS-1$ //$NON-NLS-2$
            // Canonical list_item layout name: don't warn about these, it's
            // pretty common to want to paint custom list item backgrounds
            return;
        }

        if (!context.getProject().getReportIssues()) {
            // If this is a library project not being analyzed, ignore it
            return;
        }

        Location location = context.getLocation(attribute);
        location.setClientData(attribute);
        if (mRootAttributes == null) {
            mRootAttributes = new ArrayList<Pair<Location,String>>();
        }
        mRootAttributes.add(Pair.of(location, attribute.getValue()));

        String activity = documentElement.getAttributeNS(TOOLS_URI, ATTR_CONTEXT);
        if (activity != null && !activity.isEmpty()) {
            if (activity.startsWith(".")) { //$NON-NLS-1$
                activity = context.getProject().getPackage() + activity;
            }
            registerLayoutActivity(LintUtils.getLayoutName(context.file), activity);
        }
    }
}
 
Example 7
Source File: LabelForDetector.java    From javaide with GNU General Public License v3.0 4 votes vote down vote up
@Override
public void afterCheckFile(@NonNull Context context) {
    if (mTextFields != null) {
        if (mLabels == null) {
            mLabels = Collections.emptySet();
        }

        for (Element element : mTextFields) {
            if (element.hasAttributeNS(ANDROID_URI, ATTR_HINT)) {
                continue;
            }
            String id = element.getAttributeNS(ANDROID_URI, ATTR_ID);
            boolean missing = true;
            if (mLabels.contains(id)) {
                missing = false;
            } else if (id.startsWith(NEW_ID_PREFIX)) {
                missing = !mLabels.contains(ID_PREFIX + stripIdPrefix(id));
            } else if (id.startsWith(ID_PREFIX)) {
                missing = !mLabels.contains(NEW_ID_PREFIX + stripIdPrefix(id));
            }

            if (missing) {
                XmlContext xmlContext = (XmlContext) context;
                Location location = xmlContext.getLocation(element);
                String message;
                if (id == null || id.isEmpty()) {
                    message = "No label views point to this text field with a " +
                            "`labelFor` attribute";
                } else {
                    message = String.format("No label views point to this text field with " +
                            "an `android:labelFor=\"@+id/%1$s\"` attribute", id);
                }
                xmlContext.report(ISSUE, element, location, message);
            }

        }
    }

    mLabels = null;
    mTextFields = null;
}
 
Example 8
Source File: ExtraTextDetector.java    From javaide with GNU General Public License v3.0 4 votes vote down vote up
private void visitNode(XmlContext context, Node node) {
    short nodeType = node.getNodeType();
    if (nodeType == Node.TEXT_NODE && !mFoundText) {
        String text = node.getNodeValue();
        for (int i = 0, n = text.length(); i < n; i++) {
            char c = text.charAt(i);
            if (!Character.isWhitespace(c)) {
                String snippet = text.trim();
                int maxLength = 100;
                if (snippet.length() > maxLength) {
                    snippet = snippet.substring(0, maxLength) + "...";
                }
                Location location = context.getLocation(node);
                if (i > 0) {
                    // Adjust the error position to point to the beginning of
                    // the text rather than the beginning of the text node
                    // (which is often the newline at the end of the previous
                    // line and the indentation)
                    Position start = location.getStart();
                    if (start != null) {
                        int line = start.getLine();
                        int column = start.getColumn();
                        int offset = start.getOffset();

                        for (int j = 0; j < i; j++) {
                            offset++;

                            if (text.charAt(j) == '\n') {
                                if (line != -1) {
                                    line++;
                                }
                                if (column != -1) {
                                    column = 0;
                                }
                            } else if (column != -1) {
                                column++;
                            }
                        }

                        start = new DefaultPosition(line, column, offset);
                        location = Location.create(context.file, start, location.getEnd());
                    }
                }
                context.report(ISSUE, node, location,
                        String.format("Unexpected text found in layout file: \"%1$s\"",
                                snippet));
                mFoundText = true;
                break;
            }
        }
    }

    // Visit children
    NodeList childNodes = node.getChildNodes();
    for (int i = 0, n = childNodes.getLength(); i < n; i++) {
        Node child = childNodes.item(i);
        visitNode(context, child);
    }
}
 
Example 9
Source File: TextViewDetector.java    From javaide with GNU General Public License v3.0 4 votes vote down vote up
@Override
public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
    if (element.getTagName().equals(TEXT_VIEW)) {
        if (!element.hasAttributeNS(ANDROID_URI, ATTR_TEXT)
                && element.hasAttributeNS(ANDROID_URI, ATTR_ID)
                && !element.hasAttributeNS(ANDROID_URI, ATTR_TEXT_IS_SELECTABLE)
                && !element.hasAttributeNS(ANDROID_URI, ATTR_VISIBILITY)
                && !element.hasAttributeNS(ANDROID_URI, ATTR_ON_CLICK)
                && context.getMainProject().getTargetSdk() >= 11
                && context.isEnabled(SELECTABLE)) {
            context.report(SELECTABLE, element, context.getLocation(element),
                    "Consider making the text value selectable by specifying " +
                    "`android:textIsSelectable=\"true\"`");
        }
    }

    NamedNodeMap attributes = element.getAttributes();
    for (int i = 0, n = attributes.getLength(); i < n; i++) {
        Attr attribute = (Attr) attributes.item(i);
        String name = attribute.getLocalName();
        if (name == null || name.isEmpty()) {
            // Attribute not in a namespace; we only care about the android: ones
            continue;
        }

        boolean isEditAttribute = false;
        switch (name.charAt(0)) {
            case 'a': {
                isEditAttribute = name.equals(ATTR_AUTO_TEXT);
                break;
            }
            case 'b': {
                isEditAttribute = name.equals(ATTR_BUFFER_TYPE) &&
                        attribute.getValue().equals(VALUE_EDITABLE);
                break;
            }
            case 'p': {
                isEditAttribute = name.equals(ATTR_PASSWORD)
                        || name.equals(ATTR_PHONE_NUMBER)
                        || name.equals(ATTR_PRIVATE_IME_OPTIONS);
                break;
            }
            case 'c': {
                isEditAttribute = name.equals(ATTR_CAPITALIZE)
                        || name.equals(ATTR_CURSOR_VISIBLE);
                break;
            }
            case 'd': {
                isEditAttribute = name.equals(ATTR_DIGITS);
                break;
            }
            case 'e': {
                if (name.equals(ATTR_EDITABLE)) {
                    isEditAttribute = attribute.getValue().equals(VALUE_TRUE);
                } else {
                    isEditAttribute = name.equals(ATTR_EDITOR_EXTRAS);
                }
                break;
            }
            case 'i': {
                if (name.equals(ATTR_INPUT_TYPE)) {
                    String value = attribute.getValue();
                    isEditAttribute = !value.isEmpty() && !value.equals(VALUE_NONE);
                } else {
                    isEditAttribute = name.equals(ATTR_INPUT_TYPE)
                            || name.equals(ATTR_IME_OPTIONS)
                            || name.equals(ATTR_IME_ACTION_LABEL)
                            || name.equals(ATTR_IME_ACTION_ID)
                            || name.equals(ATTR_INPUT_METHOD);
                }
                break;
            }
            case 'n': {
                isEditAttribute = name.equals(ATTR_NUMERIC);
                break;
            }
        }

        if (isEditAttribute && ANDROID_URI.equals(attribute.getNamespaceURI()) && context.isEnabled(ISSUE)) {
            Location location = context.getLocation(attribute);
            String message;
            String view = element.getTagName();
            if (view.equals(TEXT_VIEW)) {
                message = String.format(
                        "Attribute `%1$s` should not be used with `<TextView>`: " +
                        "Change element type to `<EditText>` ?", attribute.getName());
            } else {
                message = String.format(
                        "Attribute `%1$s` should not be used with `<%2$s>`: " +
                        "intended for editable text widgets",
                        attribute.getName(), view);
            }
            context.report(ISSUE, attribute, location, message);
        }
    }
}
 
Example 10
Source File: LauncherActivityDetector.java    From lewis with Apache License 2.0 4 votes vote down vote up
/**
 * Returns true if the XML node is an activity with a launcher intent.
 *
 * @param node is the node to check.
 * @return true if the node is an activity with a launcher intent, false if not.
 */
private boolean isMainActivity(XmlContext context, Node node) {

    if (TAG_APPLICATION.equals(node.getNodeName())) {
        mApplicationTagLocation = context.getLocation(node);
    }

    if (TAG_ACTIVITY.equals(node.getNodeName())) {

        mHasActivity = true;

        for (Element activityChild : LintUtils.getChildren(node)) {
            if (TAG_INTENT_FILTER.equals(activityChild.getNodeName())) {

                boolean hasLauncherCategory = false;
                boolean hasMainAction = false;

                for (Element intentFilterChild : LintUtils.getChildren(activityChild)) {
                    // Check for category tag)
                    if (NODE_CATEGORY.equals(intentFilterChild.getNodeName())
                            && Constants.CATEGORY_NAME_LAUNCHER.equals(
                            intentFilterChild.getAttributeNS(ANDROID_URI, ATTR_NAME))) {
                        hasLauncherCategory = true;
                    }
                    // Check for action tag
                    if (NODE_ACTION.equals(intentFilterChild.getNodeName())
                            && Constants.ACTION_NAME_MAIN.equals(
                            intentFilterChild.getAttributeNS(ANDROID_URI, ATTR_NAME))) {
                        hasMainAction = true;
                    }
                }

                if (hasLauncherCategory && hasMainAction) {
                    if (mHasLauncherActivity) {
                        context.report(ISSUE_MORE_THAN_ONE_LAUNCHER, context.getLocation(node),
                                "Expecting " + ANDROID_MANIFEST_XML + " to have only one activity with a launcher intent.");
                    }

                    // if it is a library
                    if (context.getProject() == context.getMainProject() && context.getMainProject().isLibrary()) {
                        context.report(ISSUE_LAUNCHER_ACTIVITY_IN_LIBRARY, context.getLocation(node),
                                "Expecting " + ANDROID_MANIFEST_XML + " not to have an activity with a launcher intent.");
                    }

                    return true;
                }
            }
        }
    }
    return false;
}