aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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/ManifestOrderDetector.java57
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/ManifestOrderDetectorTest.java9
-rw-r--r--lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/duplicate-manifest.xml22
4 files changed, 90 insertions, 1 deletions
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 a367cd6..720c0da 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 = 90;
+ final int initialCapacity = 91;
List<Issue> issues = new ArrayList<Issue>(initialCapacity);
issues.add(AccessibilityDetector.ISSUE);
@@ -105,6 +105,7 @@ public class BuiltinIssueRegistry extends IssueRegistry {
issues.add(ManifestOrderDetector.USES_SDK);
issues.add(ManifestOrderDetector.MULTIPLE_USES_SDK);
issues.add(ManifestOrderDetector.WRONG_PARENT);
+ issues.add(ManifestOrderDetector.DUPLICATE_ACTIVITY);
issues.add(SecurityDetector.EXPORTED_PROVIDER);
issues.add(SecurityDetector.EXPORTED_SERVICE);
issues.add(SecurityDetector.OPEN_PROVIDER);
diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ManifestOrderDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ManifestOrderDetector.java
index ccf6e98..cf75ae5 100644
--- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ManifestOrderDetector.java
+++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ManifestOrderDetector.java
@@ -19,6 +19,8 @@ package com.android.tools.lint.checks;
import static com.android.tools.lint.detector.api.LintConstants.ANDROID_MANIFEST_XML;
import static com.android.tools.lint.detector.api.LintConstants.ANDROID_URI;
import static com.android.tools.lint.detector.api.LintConstants.ATTR_MIN_SDK_VERSION;
+import static com.android.tools.lint.detector.api.LintConstants.ATTR_NAME;
+import static com.android.tools.lint.detector.api.LintConstants.ATTR_PACKAGE;
import static com.android.tools.lint.detector.api.LintConstants.ATTR_TARGET_SDK_VERSION;
import static com.android.tools.lint.detector.api.LintConstants.TAG_ACTIVITY;
import static com.android.tools.lint.detector.api.LintConstants.TAG_APPLICATION;
@@ -39,6 +41,7 @@ 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.Node;
import org.w3c.dom.NodeList;
@@ -47,6 +50,8 @@ import java.io.File;
import java.util.Arrays;
import java.util.Collection;
import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.Set;
/**
* Checks for issues in AndroidManifest files such as declaring elements in the
@@ -122,6 +127,22 @@ public class ManifestOrderDetector extends Detector implements Detector.XmlScann
EnumSet.of(Scope.MANIFEST)).setMoreInfo(
"http://developer.android.com/guide/topics/manifest/manifest-intro.html"); //$NON-NLS-1$
+ /** Missing a {@code <uses-sdk>} element */
+ public static final Issue DUPLICATE_ACTIVITY = Issue.create(
+ "DuplicateActivity", //$NON-NLS-1$
+ "Checks that an activity is registered only once in the manifest",
+
+ "An activity should only be registered once in the manifest. If it is " +
+ "accidentally registered more than once, then subtle errors can occur, " +
+ "since attribute declarations from the two elements are not merged, so " +
+ "you may accidentally remove previous declarations.",
+
+ Category.CORRECTNESS,
+ 5,
+ Severity.ERROR,
+ ManifestOrderDetector.class,
+ EnumSet.of(Scope.MANIFEST));
+
/** Constructs a new {@link ManifestOrderDetector} check */
public ManifestOrderDetector() {
}
@@ -131,6 +152,12 @@ public class ManifestOrderDetector extends Detector implements Detector.XmlScann
/** Number of times we've seen the <uses-sdk> element */
private int mSeenUsesSdk;
+ /** Activities we've encountered */
+ private Set<String> mActivities = new HashSet<String>();
+
+ /** Package declared in the manifest */
+ private String mPackage;
+
@Override
public Speed getSpeed() {
return Speed.FAST;
@@ -196,6 +223,28 @@ public class ManifestOrderDetector extends Detector implements Detector.XmlScann
tag), null);
}
+ if (tag.equals(TAG_ACTIVITY)) {
+ Attr nameNode = element.getAttributeNodeNS(ANDROID_URI, ATTR_NAME);
+ if (nameNode != null) {
+ String name = nameNode.getValue();
+ if (!name.isEmpty()) {
+ if (name.charAt(0) == '.') {
+ name = getPackage(element) + name;
+ } else if (name.indexOf('.') == -1) {
+ name = getPackage(element) + '.' + name;
+ }
+ if (mActivities.contains(name)) {
+ String message = String.format(
+ "Duplicate registration for activity %1$s", name);
+ context.report(DUPLICATE_ACTIVITY, context.getLocation(nameNode),
+ message, null);
+ } else {
+ mActivities.add(name);
+ }
+ }
+ }
+ }
+
return;
}
@@ -268,4 +317,12 @@ public class ManifestOrderDetector extends Detector implements Detector.XmlScann
mSeenApplication = false;
}
}
+
+ private String getPackage(Element element) {
+ if (mPackage == null) {
+ return element.getOwnerDocument().getDocumentElement().getAttribute(ATTR_PACKAGE);
+ }
+
+ return mPackage;
+ }
}
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/ManifestOrderDetectorTest.java b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/ManifestOrderDetectorTest.java
index 9553d78..54bb1f3 100644
--- a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/ManifestOrderDetectorTest.java
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/ManifestOrderDetectorTest.java
@@ -100,4 +100,13 @@ public class ManifestOrderDetectorTest extends AbstractCheckTest {
lintProject("broken-manifest2.xml=>AndroidManifest.xml"));
}
+
+ public void testDuplicateActivity() throws Exception {
+ assertEquals(
+ "AndroidManifest.xml:16: Error: Duplicate registration for activity com.example.helloworld.HelloWorld",
+
+ lintProject(
+ "duplicate-manifest.xml=>AndroidManifest.xml",
+ "res/values/strings.xml"));
+ }
}
diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/duplicate-manifest.xml b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/duplicate-manifest.xml
new file mode 100644
index 0000000..e1fc3c6
--- /dev/null
+++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/duplicate-manifest.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.example.helloworld"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <uses-sdk android:minSdkVersion="14" />
+ <application android:icon="@drawable/icon" android:label="@string/app_name">
+ <activity android:name=".HelloWorld"
+ android:label="@string/app_name">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name="com.example.helloworld.HelloWorld"
+ android:label="@string/app_name">
+ </activity>
+
+ </application>
+
+</manifest>