aboutsummaryrefslogtreecommitdiffstats
path: root/lint
diff options
context:
space:
mode:
authorTor Norbye <tnorbye@google.com>2012-02-17 11:51:48 -0800
committerTor Norbye <tnorbye@google.com>2012-02-21 14:00:21 -0800
commitf78bed2794ecbfe7bb1cea2c3f5faf57a88ea2ba (patch)
tree657d2e51417257c270471d1d086b3ed8c7dc7a06 /lint
parent556b907792f0658a6c3f676e23469b83175e3431 (diff)
downloadsdk-f78bed2794ecbfe7bb1cea2c3f5faf57a88ea2ba.zip
sdk-f78bed2794ecbfe7bb1cea2c3f5faf57a88ea2ba.tar.gz
sdk-f78bed2794ecbfe7bb1cea2c3f5faf57a88ea2ba.tar.bz2
Lint rule to catch edit-usage of TextViews (should be EditText)
TextView provides a number of attributes related to text editing. However, these are generally intended for the EditText subclass of EditText. This lint check looks for <TextView> elements in layouts where one or more of the edit-related attributes (such as inputType) are defined. It also updates the deprecation detector to check various deprecated attributes (it only checked for deprecated elements before this.) Change-Id: I1b94902d906cd0bee6a6564368125a68b3c9bb2a
Diffstat (limited to 'lint')
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/client/api/DefaultSdkInfo.java6
-rw-r--r--lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintConstants.java23
-rw-r--r--lint/libs/lint_checks/src/com/android/tools/lint/checks/BuiltinIssueRegistry.java3
-rw-r--r--lint/libs/lint_checks/src/com/android/tools/lint/checks/DeprecationDetector.java89
-rw-r--r--lint/libs/lint_checks/src/com/android/tools/lint/checks/TextViewDetector.java193
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/DeprecationDetectorTest.java28
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/TextViewDetectorTest.java54
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/deprecation.xml12
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/edit_textview.xml83
9 files changed, 485 insertions, 6 deletions
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/client/api/DefaultSdkInfo.java b/lint/libs/lint_api/src/com/android/tools/lint/client/api/DefaultSdkInfo.java
index 1c8b74c..930f7a7 100644
--- a/lint/libs/lint_api/src/com/android/tools/lint/client/api/DefaultSdkInfo.java
+++ b/lint/libs/lint_api/src/com/android/tools/lint/client/api/DefaultSdkInfo.java
@@ -22,6 +22,7 @@ import static com.android.tools.lint.detector.api.LintConstants.ABS_SEEK_BAR;
import static com.android.tools.lint.detector.api.LintConstants.ABS_SPINNER;
import static com.android.tools.lint.detector.api.LintConstants.ADAPTER_VIEW;
import static com.android.tools.lint.detector.api.LintConstants.BUTTON;
+import static com.android.tools.lint.detector.api.LintConstants.CHECKED_TEXT_VIEW;
import static com.android.tools.lint.detector.api.LintConstants.CHECK_BOX;
import static com.android.tools.lint.detector.api.LintConstants.COMPOUND_BUTTON;
import static com.android.tools.lint.detector.api.LintConstants.EDIT_TEXT;
@@ -42,6 +43,7 @@ import static com.android.tools.lint.detector.api.LintConstants.SCROLL_VIEW;
import static com.android.tools.lint.detector.api.LintConstants.SEEK_BAR;
import static com.android.tools.lint.detector.api.LintConstants.SPINNER;
import static com.android.tools.lint.detector.api.LintConstants.SURFACE_VIEW;
+import static com.android.tools.lint.detector.api.LintConstants.SWITCH;
import static com.android.tools.lint.detector.api.LintConstants.TABLE_LAYOUT;
import static com.android.tools.lint.detector.api.LintConstants.TABLE_ROW;
import static com.android.tools.lint.detector.api.LintConstants.TAB_HOST;
@@ -126,7 +128,7 @@ class DefaultSdkInfo extends SdkInfo {
return false;
}
- private static final int CLASS_COUNT = 57;
+ private static final int CLASS_COUNT = 59;
@NonNull
private static final Map<String, String> PARENTS = new HashMap<String, String>(CLASS_COUNT);
@@ -140,6 +142,7 @@ class DefaultSdkInfo extends SdkInfo {
PARENTS.put(VIEW_GROUP, VIEW);
PARENTS.put(TEXT_VIEW, VIEW);
+ PARENTS.put(CHECKED_TEXT_VIEW, TEXT_VIEW);
PARENTS.put(RADIO_BUTTON, COMPOUND_BUTTON);
PARENTS.put(SPINNER, ABS_SPINNER);
PARENTS.put(IMAGE_BUTTON, IMAGE_VIEW);
@@ -151,6 +154,7 @@ class DefaultSdkInfo extends SdkInfo {
PARENTS.put(BUTTON, TEXT_VIEW);
PARENTS.put(SEEK_BAR, ABS_SEEK_BAR);
PARENTS.put(CHECK_BOX, COMPOUND_BUTTON);
+ PARENTS.put(SWITCH, COMPOUND_BUTTON);
PARENTS.put(GALLERY, ABS_SPINNER);
PARENTS.put(SURFACE_VIEW, VIEW);
PARENTS.put(ABSOLUTE_LAYOUT, VIEW_GROUP);
diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintConstants.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintConstants.java
index 7d2c35a..b3eb1b7 100644
--- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintConstants.java
+++ b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintConstants.java
@@ -78,9 +78,11 @@ public class LintConstants {
public static final String TAB_HOST = "TabHost"; //$NON-NLS-1$
public static final String RADIO_GROUP = "RadioGroup"; //$NON-NLS-1$
public static final String RADIO_BUTTON = "RadioButton"; //$NON-NLS-1$
+ public static final String SWITCH = "Switch"; //$NON-NLS-1$
public static final String EDIT_TEXT = "EditText"; //$NON-NLS-1$
public static final String LIST_VIEW = "ListView"; //$NON-NLS-1$
public static final String TEXT_VIEW = "TextView"; //$NON-NLS-1$
+ public static final String CHECKED_TEXT_VIEW = "CheckedTextView"; //$NON-NLS-1$
public static final String IMAGE_VIEW = "ImageView"; //$NON-NLS-1$
public static final String SURFACE_VIEW = "SurfaceView"; //$NON-NLS-1$
public static final String ABSOLUTE_LAYOUT = "AbsoluteLayout"; //$NON-NLS-1$
@@ -153,8 +155,26 @@ public class LintConstants {
public static final String ATTR_LAYOUT = "layout"; //$NON-NLS-1$
public static final String ATTR_ROW_COUNT = "rowCount"; //$NON-NLS-1$
public static final String ATTR_COLUMN_COUNT = "columnCount"; //$NON-NLS-1$
- public static final String ATTR_BASELINE_ALIGNED = "baselineAligned"; //$NON-NLS-1$
+ public static final String ATTR_BASELINE_ALIGNED = "baselineAligned"; //$NON-NLS-1$
public static final String ATTR_CONTENT_DESCRIPTION = "contentDescription"; //$NON-NLS-1$
+ public static final String ATTR_IME_ACTION_LABEL = "imeActionLabel"; //$NON-NLS-1$
+ public static final String ATTR_PRIVATE_IME_OPTIONS = "privateImeOptions"; //$NON-NLS-1$
+ public static final String VALUE_NONE = "none"; //$NON-NLS-1$
+ public static final String ATTR_NUMERIC = "numeric"; //$NON-NLS-1$
+ public static final String ATTR_IME_ACTION_ID = "imeActionId"; //$NON-NLS-1$
+ public static final String ATTR_IME_OPTIONS = "imeOptions"; //$NON-NLS-1$
+ public static final String ATTR_FREEZES_TEXT = "freezesText"; //$NON-NLS-1$
+ public static final String ATTR_EDITOR_EXTRAS = "editorExtras"; //$NON-NLS-1$
+ public static final String ATTR_EDITABLE = "editable"; //$NON-NLS-1$
+ public static final String ATTR_DIGITS = "digits"; //$NON-NLS-1$
+ public static final String ATTR_CURSOR_VISIBLE = "cursorVisible"; //$NON-NLS-1$
+ public static final String ATTR_CAPITALIZE = "capitalize"; //$NON-NLS-1$
+ public static final String ATTR_PHONE_NUMBER = "phoneNumber"; //$NON-NLS-1$
+ public static final String ATTR_PASSWORD = "password"; //$NON-NLS-1$
+ public static final String ATTR_BUFFER_TYPE = "bufferType"; //$NON-NLS-1$
+ public static final String ATTR_AUTO_TEXT = "autoText"; //$NON-NLS-1$
+ public static final String ATTR_ENABLED = "enabled"; //$NON-NLS-1$
+ public static final String ATTR_SINGLE_LINE = "singleLine"; //$NON-NLS-1$
// AbsoluteLayout layout params
public static final String ATTR_LAYOUT_Y = "layout_y"; //$NON-NLS-1$
@@ -203,6 +223,7 @@ public class LintConstants {
public static final String VALUE_MATCH_PARENT = "match_parent"; //$NON-NLS-1$
public static final String VALUE_VERTICAL = "vertical"; //$NON-NLS-1$
public static final String VALUE_TRUE = "true"; //$NON-NLS-1$
+ public static final String VALUE_EDITABLE = "editable"; //$NON-NLS-1$
// Values: Resources
diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/BuiltinIssueRegistry.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/BuiltinIssueRegistry.java
index cdb4c12..6f8f19b 100644
--- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/BuiltinIssueRegistry.java
+++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/BuiltinIssueRegistry.java
@@ -53,7 +53,7 @@ public class BuiltinIssueRegistry extends IssueRegistry {
private static final List<Issue> sIssues;
static {
- final int initialCapacity = 79;
+ final int initialCapacity = 80;
List<Issue> issues = new ArrayList<Issue>(initialCapacity);
issues.add(AccessibilityDetector.ISSUE);
@@ -92,6 +92,7 @@ public class BuiltinIssueRegistry extends IssueRegistry {
issues.add(ProguardDetector.ISSUE);
issues.add(PxUsageDetector.ISSUE);
issues.add(TextFieldDetector.ISSUE);
+ issues.add(TextViewDetector.ISSUE);
issues.add(UnusedResourceDetector.ISSUE);
issues.add(UnusedResourceDetector.ISSUE_IDS);
issues.add(ExtraTextDetector.ISSUE);
diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/DeprecationDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/DeprecationDetector.java
index 883afc7..c60c8e0 100644
--- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/DeprecationDetector.java
+++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/DeprecationDetector.java
@@ -17,6 +17,16 @@
package com.android.tools.lint.checks;
import static com.android.tools.lint.detector.api.LintConstants.ABSOLUTE_LAYOUT;
+import static com.android.tools.lint.detector.api.LintConstants.ANDROID_URI;
+import static com.android.tools.lint.detector.api.LintConstants.ATTR_AUTO_TEXT;
+import static com.android.tools.lint.detector.api.LintConstants.ATTR_CAPITALIZE;
+import static com.android.tools.lint.detector.api.LintConstants.ATTR_EDITABLE;
+import static com.android.tools.lint.detector.api.LintConstants.ATTR_ENABLED;
+import static com.android.tools.lint.detector.api.LintConstants.ATTR_INPUT_METHOD;
+import static com.android.tools.lint.detector.api.LintConstants.ATTR_NUMERIC;
+import static com.android.tools.lint.detector.api.LintConstants.ATTR_PASSWORD;
+import static com.android.tools.lint.detector.api.LintConstants.ATTR_PHONE_NUMBER;
+import static com.android.tools.lint.detector.api.LintConstants.ATTR_SINGLE_LINE;
import com.android.tools.lint.detector.api.Category;
import com.android.tools.lint.detector.api.Issue;
@@ -26,8 +36,10 @@ import com.android.tools.lint.detector.api.Severity;
import com.android.tools.lint.detector.api.Speed;
import com.android.tools.lint.detector.api.XmlContext;
+import org.w3c.dom.Attr;
import org.w3c.dom.Element;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@@ -64,8 +76,85 @@ public class DeprecationDetector extends LayoutDetector {
}
@Override
+ public Collection<String> getApplicableAttributes() {
+ return Arrays.asList(
+ // TODO: fill_parent is deprecated as of API 8.
+ // We could warn about it, but it will probably be very noisy
+ // and make people disable the deprecation check; let's focus on
+ // some older flags for now
+ //"fill_parent",
+
+ ATTR_EDITABLE,
+ ATTR_INPUT_METHOD,
+ ATTR_AUTO_TEXT,
+ ATTR_CAPITALIZE,
+
+ // This flag is still used a lot and is still properly handled by TextView
+ // so in the interest of not being too noisy and make people ignore all the
+ // output, keep quiet about this one -for now-.
+ //ATTR_SINGLE_LINE,
+
+ ATTR_ENABLED,
+ ATTR_NUMERIC,
+ ATTR_PHONE_NUMBER,
+ ATTR_PASSWORD
+
+ // These attributes are also deprecated; not yet enabled until we
+ // know the API level to apply the deprecation for:
+
+ // "ignored as of ICS (but deprecated earlier)"
+ //"fadingEdge",
+
+ // "This attribute is not used by the Android operating system."
+ //"restoreNeedsApplication",
+
+ // "This will create a non-standard UI appearance, because the search bar UI is
+ // changing to use only icons for its buttons."
+ //"searchButtonText",
+
+ );
+ }
+
+ @Override
public void visitElement(XmlContext context, Element element) {
context.report(ISSUE, element, context.getLocation(element),
String.format("%1$s is deprecated", element.getTagName()), null);
}
+
+ @Override
+ public void visitAttribute(XmlContext context, Attr attribute) {
+ if (!ANDROID_URI.equals(attribute.getNamespaceURI())) {
+ return;
+ }
+
+ String name = attribute.getLocalName();
+ String fix;
+ int minSdk = 1;
+ if (name.equals(ATTR_EDITABLE)) {
+ fix = "Use an <EditText> to make it editable";
+ } else if (name.equals(ATTR_ENABLED)) {
+ fix = "Use state_enabled instead";
+ } else if (name.equals(ATTR_SINGLE_LINE)) {
+ fix = "Use maxLines=\"1\" instead";
+ } else {
+ assert name.equals(ATTR_INPUT_METHOD)
+ || name.equals(ATTR_CAPITALIZE)
+ || name.equals(ATTR_NUMERIC)
+ || name.equals(ATTR_PHONE_NUMBER)
+ || name.equals(ATTR_PASSWORD)
+ || name.equals(ATTR_AUTO_TEXT);
+ fix = "Use inputType instead";
+ // The inputType attribute was introduced in API 3 so don't warn about
+ // deprecation if targeting older platforms
+ minSdk = 3;
+ }
+
+ if (context.getProject().getMinSdk() < minSdk) {
+ return;
+ }
+
+ context.report(ISSUE, attribute, context.getLocation(attribute),
+ String.format("%1$s is deprecated: %2$s",
+ attribute.getName(), fix), null);
+ }
}
diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/TextViewDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/TextViewDetector.java
new file mode 100644
index 0000000..09608b1
--- /dev/null
+++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/TextViewDetector.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+package com.android.tools.lint.checks;
+
+import static com.android.tools.lint.detector.api.LintConstants.ANDROID_URI;
+import static com.android.tools.lint.detector.api.LintConstants.ATTR_AUTO_TEXT;
+import static com.android.tools.lint.detector.api.LintConstants.ATTR_BUFFER_TYPE;
+import static com.android.tools.lint.detector.api.LintConstants.ATTR_CAPITALIZE;
+import static com.android.tools.lint.detector.api.LintConstants.ATTR_CURSOR_VISIBLE;
+import static com.android.tools.lint.detector.api.LintConstants.ATTR_DIGITS;
+import static com.android.tools.lint.detector.api.LintConstants.ATTR_EDITABLE;
+import static com.android.tools.lint.detector.api.LintConstants.ATTR_EDITOR_EXTRAS;
+import static com.android.tools.lint.detector.api.LintConstants.ATTR_IME_ACTION_ID;
+import static com.android.tools.lint.detector.api.LintConstants.ATTR_IME_ACTION_LABEL;
+import static com.android.tools.lint.detector.api.LintConstants.ATTR_IME_OPTIONS;
+import static com.android.tools.lint.detector.api.LintConstants.ATTR_INPUT_METHOD;
+import static com.android.tools.lint.detector.api.LintConstants.ATTR_INPUT_TYPE;
+import static com.android.tools.lint.detector.api.LintConstants.ATTR_NUMERIC;
+import static com.android.tools.lint.detector.api.LintConstants.ATTR_PASSWORD;
+import static com.android.tools.lint.detector.api.LintConstants.ATTR_PHONE_NUMBER;
+import static com.android.tools.lint.detector.api.LintConstants.ATTR_PRIVATE_IME_OPTIONS;
+import static com.android.tools.lint.detector.api.LintConstants.BUTTON;
+import static com.android.tools.lint.detector.api.LintConstants.CHECKED_TEXT_VIEW;
+import static com.android.tools.lint.detector.api.LintConstants.CHECK_BOX;
+import static com.android.tools.lint.detector.api.LintConstants.RADIO_BUTTON;
+import static com.android.tools.lint.detector.api.LintConstants.SWITCH;
+import static com.android.tools.lint.detector.api.LintConstants.TEXT_VIEW;
+import static com.android.tools.lint.detector.api.LintConstants.TOGGLE_BUTTON;
+import static com.android.tools.lint.detector.api.LintConstants.VALUE_EDITABLE;
+import static com.android.tools.lint.detector.api.LintConstants.VALUE_NONE;
+import static com.android.tools.lint.detector.api.LintConstants.VALUE_TRUE;
+
+import com.android.tools.lint.detector.api.Category;
+import com.android.tools.lint.detector.api.Issue;
+import com.android.tools.lint.detector.api.LayoutDetector;
+import com.android.tools.lint.detector.api.Location;
+import com.android.tools.lint.detector.api.Scope;
+import com.android.tools.lint.detector.api.Severity;
+import com.android.tools.lint.detector.api.Speed;
+import com.android.tools.lint.detector.api.XmlContext;
+
+import org.w3c.dom.Attr;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+
+import java.util.Arrays;
+import java.util.Collection;
+
+/**
+ * Checks for cases where a TextView should probably be an EditText instead
+ */
+public class TextViewDetector extends LayoutDetector {
+ /** The main issue discovered by this detector */
+ public static final Issue ISSUE = Issue.create(
+ "TextViewEdits", //$NON-NLS-1$
+ "Looks for TextViews being used for input",
+
+ "Using a <TextView> to input text is generally an error, you should be " +
+ "using <EditText> instead. EditText is a subclass of TextView, and some " +
+ "of the editing support is provided by TextView, so it's possible to set " +
+ "some input-related properties on a TextView. However, using a TextView " +
+ "along with input attributes is usually a cut & paste error. To input " +
+ "text you should be using <EditText>." +
+ "\n" +
+ "This check also checks subclasses of TextView, such as Button and CheckBox, " +
+ "since these have the same issue: they should not be used with editable " +
+ "attributes.",
+
+ Category.CORRECTNESS,
+ 7,
+ Severity.WARNING,
+ TextViewDetector.class,
+ Scope.RESOURCE_FILE_SCOPE);
+
+ /** Constructs a new {@link TextViewDetector} */
+ public TextViewDetector() {
+ }
+
+ @Override
+ public Speed getSpeed() {
+ return Speed.FAST;
+ }
+
+ @Override
+ public Collection<String> getApplicableElements() {
+ return Arrays.asList(
+ TEXT_VIEW,
+ BUTTON,
+ TOGGLE_BUTTON,
+ CHECK_BOX,
+ RADIO_BUTTON,
+ CHECKED_TEXT_VIEW,
+ SWITCH
+ );
+ }
+
+ @Override
+ public void visitElement(XmlContext context, Element element) {
+ 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) {
+ // 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())) {
+ 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, null);
+ }
+ }
+ }
+}
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/DeprecationDetectorTest.java b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/DeprecationDetectorTest.java
index b0adceb..88c5f60 100644
--- a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/DeprecationDetectorTest.java
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/DeprecationDetectorTest.java
@@ -25,9 +25,31 @@ public class DeprecationDetectorTest extends AbstractCheckTest {
return new DeprecationDetector();
}
- public void testAbsoluteLayout() throws Exception {
+ public void testApi1() throws Exception {
assertEquals(
- "deprecation.xml:2: Warning: AbsoluteLayout is deprecated",
- lintProject("res/layout/deprecation.xml"));
+ "deprecation.xml:18: Warning: android:editable is deprecated: Use an <EditText> to make it editable\n" +
+ "deprecation.xml:19: Warning: android:enabled is deprecated: Use state_enabled instead\n" +
+ "deprecation.xml:2: Warning: AbsoluteLayout is deprecated",
+
+ lintProject(
+ "apicheck/minsdk1.xml=>AndroidManifest.xml",
+ "res/layout/deprecation.xml"));
+ }
+
+ public void testApi4() throws Exception {
+ assertEquals(
+ "deprecation.xml:16: Warning: android:autoText is deprecated: Use inputType instead\n" +
+ "deprecation.xml:17: Warning: android:capitalize is deprecated: Use inputType instead\n" +
+ "deprecation.xml:18: Warning: android:editable is deprecated: Use an <EditText> to make it editable\n" +
+ "deprecation.xml:19: Warning: android:enabled is deprecated: Use state_enabled instead\n" +
+ "deprecation.xml:20: Warning: android:inputMethod is deprecated: Use inputType instead\n" +
+ "deprecation.xml:21: Warning: android:numeric is deprecated: Use inputType instead\n" +
+ "deprecation.xml:22: Warning: android:password is deprecated: Use inputType instead\n" +
+ "deprecation.xml:23: Warning: android:phoneNumber is deprecated: Use inputType instead\n" +
+ "deprecation.xml:2: Warning: AbsoluteLayout is deprecated",
+
+ lintProject(
+ "apicheck/minsdk4.xml=>AndroidManifest.xml",
+ "res/layout/deprecation.xml"));
}
}
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/TextViewDetectorTest.java b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/TextViewDetectorTest.java
new file mode 100644
index 0000000..a0bbb50
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/TextViewDetectorTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+package com.android.tools.lint.checks;
+
+import com.android.tools.lint.detector.api.Detector;
+
+@SuppressWarnings("javadoc")
+public class TextViewDetectorTest extends AbstractCheckTest {
+ @Override
+ protected Detector getDetector() {
+ return new TextViewDetector();
+ }
+
+ public void test() throws Exception {
+ assertEquals(
+ "edit_textview.xml:13: Warning: Attribute android:autoText should not be used with <TextView>: Change element type to <EditText> ?\n" +
+ "edit_textview.xml:14: Warning: Attribute android:bufferType should not be used with <TextView>: Change element type to <EditText> ?\n" +
+ "edit_textview.xml:15: Warning: Attribute android:capitalize should not be used with <TextView>: Change element type to <EditText> ?\n" +
+ "edit_textview.xml:16: Warning: Attribute android:cursorVisible should not be used with <TextView>: Change element type to <EditText> ?\n" +
+ "edit_textview.xml:17: Warning: Attribute android:digits should not be used with <TextView>: Change element type to <EditText> ?\n" +
+ "edit_textview.xml:18: Warning: Attribute android:editable should not be used with <TextView>: Change element type to <EditText> ?\n" +
+ "edit_textview.xml:19: Warning: Attribute android:editorExtras should not be used with <TextView>: Change element type to <EditText> ?\n" +
+ "edit_textview.xml:22: Warning: Attribute android:imeActionId should not be used with <TextView>: Change element type to <EditText> ?\n" +
+ "edit_textview.xml:23: Warning: Attribute android:imeActionLabel should not be used with <TextView>: Change element type to <EditText> ?\n" +
+ "edit_textview.xml:24: Warning: Attribute android:imeOptions should not be used with <TextView>: Change element type to <EditText> ?\n" +
+ "edit_textview.xml:25: Warning: Attribute android:inputMethod should not be used with <TextView>: Change element type to <EditText> ?\n" +
+ "edit_textview.xml:26: Warning: Attribute android:inputType should not be used with <TextView>: Change element type to <EditText> ?\n" +
+ "edit_textview.xml:27: Warning: Attribute android:numeric should not be used with <TextView>: Change element type to <EditText> ?\n" +
+ "edit_textview.xml:28: Warning: Attribute android:password should not be used with <TextView>: Change element type to <EditText> ?\n" +
+ "edit_textview.xml:29: Warning: Attribute android:phoneNumber should not be used with <TextView>: Change element type to <EditText> ?\n" +
+ "edit_textview.xml:30: Warning: Attribute android:privateImeOptions should not be used with <TextView>: Change element type to <EditText> ?\n" +
+ "edit_textview.xml:38: Warning: Attribute android:cursorVisible should not be used with <Button>: intended for editable text widgets\n" +
+ "edit_textview.xml:44: Warning: Attribute android:cursorVisible should not be used with <CheckedTextView>: intended for editable text widgets\n" +
+ "edit_textview.xml:50: Warning: Attribute android:cursorVisible should not be used with <CheckBox>: intended for editable text widgets\n" +
+ "edit_textview.xml:56: Warning: Attribute android:cursorVisible should not be used with <RadioButton>: intended for editable text widgets\n" +
+ "edit_textview.xml:62: Warning: Attribute android:cursorVisible should not be used with <ToggleButton>: intended for editable text widgets",
+
+ lintFiles("res/layout/edit_textview.xml"));
+ }
+}
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/deprecation.xml b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/deprecation.xml
index cbd03df..74a78ff 100644
--- a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/deprecation.xml
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/deprecation.xml
@@ -11,4 +11,16 @@
android:layout_y="100dp"
android:text="Button" />
+ <!-- Deprecated attributes -->
+ <TextView
+ android:autoText="true"
+ android:capitalize="true"
+ android:editable="true"
+ android:enabled="true"
+ android:inputMethod="@+id/foo"
+ android:numeric="true"
+ android:password="true"
+ android:phoneNumber="true"
+ android:singleLine="true" />
+
</AbsoluteLayout>
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/edit_textview.xml b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/edit_textview.xml
new file mode 100644
index 0000000..39aa4b7
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/res/layout/edit_textview.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical" >
+
+ <!-- Various attributes that should be set on EditTexts, not TextViews -->
+
+ <TextView
+ android:id="@+id/textview"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:autoText="true"
+ android:bufferType="editable"
+ android:capitalize="words"
+ android:cursorVisible="true"
+ android:digits=""
+ android:editable="true"
+ android:editorExtras="@+id/foobar"
+ android:focusable="true"
+ android:focusableInTouchMode="true"
+ android:imeActionId="@+id/foo"
+ android:imeActionLabel=""
+ android:imeOptions=""
+ android:inputMethod=""
+ android:inputType="text"
+ android:numeric=""
+ android:password="true"
+ android:phoneNumber="true"
+ android:privateImeOptions="" />
+
+ <!-- Various attributes that should be set on EditTexts, not Buttons -->
+
+ <Button
+ android:id="@+id/button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:cursorVisible="true" />
+
+ <CheckedTextView
+ android:id="@+id/checkedTextView"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:cursorVisible="true" />
+
+ <CheckBox
+ android:id="@+id/checkbox"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:cursorVisible="true" />
+
+ <RadioButton
+ android:id="@+id/radioButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:cursorVisible="true" />
+
+ <ToggleButton
+ android:id="@+id/toggleButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:cursorVisible="true" />
+
+
+ <!-- Ok #1 -->
+
+ <TextView
+ android:id="@+id/okTextView1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:bufferType="spannable"
+ android:freezesText="true"
+ android:editable="false"
+ android:inputType="none" />
+
+ <!-- Ok #2 -->
+
+ <TextView
+ android:id="@+id/okTextView2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+</LinearLayout>