aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lint/cli/src/test/java/com/android/tools/lint/checks/ManifestOrderDetectorTest.java32
-rw-r--r--lint/cli/src/test/java/com/android/tools/lint/checks/data/illegal_version.xml23
-rw-r--r--lint/cli/src/test/java/com/android/tools/lint/checks/data/no_version.xml21
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/BuiltinIssueRegistry.java4
-rw-r--r--lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ManifestOrderDetector.java85
5 files changed, 161 insertions, 4 deletions
diff --git a/lint/cli/src/test/java/com/android/tools/lint/checks/ManifestOrderDetectorTest.java b/lint/cli/src/test/java/com/android/tools/lint/checks/ManifestOrderDetectorTest.java
index 8508d40..e845b57 100644
--- a/lint/cli/src/test/java/com/android/tools/lint/checks/ManifestOrderDetectorTest.java
+++ b/lint/cli/src/test/java/com/android/tools/lint/checks/ManifestOrderDetectorTest.java
@@ -287,4 +287,36 @@ public class ManifestOrderDetectorTest extends AbstractCheckTest {
checkLint(Arrays.asList(master, library)));
}
+ public void testMissingVersion() throws Exception {
+ mEnabled = Collections.singleton(ManifestOrderDetector.SET_VERSION);
+ assertEquals(""
+ + "AndroidManifest.xml:2: Warning: Should set android:versionCode to specify the application version [MissingVersion]\n"
+ + "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ + "^\n"
+ + "AndroidManifest.xml:2: Warning: Should set android:versionName to specify the application version [MissingVersion]\n"
+ + "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ + "^\n"
+ + "0 errors, 2 warnings\n",
+ lintProject("no_version.xml=>AndroidManifest.xml"));
+ }
+
+ public void testIllegalReference() throws Exception {
+ mEnabled = Collections.singleton(ManifestOrderDetector.ILLEGAL_REFERENCE);
+ assertEquals(""
+ + "AndroidManifest.xml:2: Warning: The android:versionCode cannot be a resource url, it must be a literal integer [IllegalResourceRef]\n"
+ + "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ + "^\n"
+ + "AndroidManifest.xml:2: Warning: The android:versionName cannot be a resource url, it must be a literal string [IllegalResourceRef]\n"
+ + "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ + "^\n"
+ + "AndroidManifest.xml:7: Warning: The android:minSdkVersion cannot be a resource url, it must be a literal integer (or string if a preview codename) [IllegalResourceRef]\n"
+ + " <uses-sdk android:minSdkVersion=\"@dimen/minSdkVersion\" android:targetSdkVersion=\"@dimen/targetSdkVersion\" />\n"
+ + " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"
+ + "AndroidManifest.xml:7: Warning: The android:targetSdkVersion cannot be a resource url, it must be a literal integer (or string if a preview codename) [IllegalResourceRef]\n"
+ + " <uses-sdk android:minSdkVersion=\"@dimen/minSdkVersion\" android:targetSdkVersion=\"@dimen/targetSdkVersion\" />\n"
+ + " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"
+ + "0 errors, 4 warnings\n",
+
+ lintProject("illegal_version.xml=>AndroidManifest.xml"));
+ }
}
diff --git a/lint/cli/src/test/java/com/android/tools/lint/checks/data/illegal_version.xml b/lint/cli/src/test/java/com/android/tools/lint/checks/data/illegal_version.xml
new file mode 100644
index 0000000..3028117
--- /dev/null
+++ b/lint/cli/src/test/java/com/android/tools/lint/checks/data/illegal_version.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="foo.bar2"
+ android:versionCode="@dimen/versionCode"
+ android:versionName="@dimen/versionName" >
+
+ <uses-sdk android:minSdkVersion="@dimen/minSdkVersion" android:targetSdkVersion="@dimen/targetSdkVersion" />
+
+ <application
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name" >
+ <activity
+ android:label="@string/app_name"
+ android:name=".Foo2Activity" >
+ <intent-filter >
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
diff --git a/lint/cli/src/test/java/com/android/tools/lint/checks/data/no_version.xml b/lint/cli/src/test/java/com/android/tools/lint/checks/data/no_version.xml
new file mode 100644
index 0000000..1c3c0a4
--- /dev/null
+++ b/lint/cli/src/test/java/com/android/tools/lint/checks/data/no_version.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="foo.bar2" >
+
+ <uses-sdk android:minSdkVersion="14" />
+
+ <application
+ android:icon="@drawable/ic_launcher"
+ android:label="@string/app_name" >
+ <activity
+ android:label="@string/app_name"
+ android:name=".Foo2Activity" >
+ <intent-filter >
+ <action android:name="android.intent.action.MAIN" />
+
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+
+</manifest>
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/BuiltinIssueRegistry.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/BuiltinIssueRegistry.java
index 71866c3..b1ce430 100644
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/BuiltinIssueRegistry.java
+++ b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/BuiltinIssueRegistry.java
@@ -55,7 +55,7 @@ public class BuiltinIssueRegistry extends IssueRegistry {
private static final List<Issue> sIssues;
static {
- final int initialCapacity = 134;
+ final int initialCapacity = 136;
List<Issue> issues = new ArrayList<Issue>(initialCapacity);
issues.add(AccessibilityDetector.ISSUE);
@@ -132,6 +132,8 @@ public class BuiltinIssueRegistry extends IssueRegistry {
issues.add(ManifestOrderDetector.TARGET_NEWER);
issues.add(ManifestOrderDetector.ALLOW_BACKUP);
issues.add(ManifestOrderDetector.UNIQUE_PERMISSION);
+ issues.add(ManifestOrderDetector.SET_VERSION);
+ issues.add(ManifestOrderDetector.ILLEGAL_REFERENCE);
issues.add(SecurityDetector.EXPORTED_PROVIDER);
issues.add(SecurityDetector.EXPORTED_SERVICE);
issues.add(SecurityDetector.EXPORTED_ACTIVITY);
diff --git a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ManifestOrderDetector.java b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ManifestOrderDetector.java
index 9762c07..83fac97 100644
--- a/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ManifestOrderDetector.java
+++ b/lint/libs/lint_checks/src/main/java/com/android/tools/lint/checks/ManifestOrderDetector.java
@@ -22,6 +22,7 @@ import static com.android.SdkConstants.ATTR_MIN_SDK_VERSION;
import static com.android.SdkConstants.ATTR_NAME;
import static com.android.SdkConstants.ATTR_PACKAGE;
import static com.android.SdkConstants.ATTR_TARGET_SDK_VERSION;
+import static com.android.SdkConstants.PREFIX_RESOURCE_REF;
import static com.android.SdkConstants.TAG_ACTIVITY;
import static com.android.SdkConstants.TAG_APPLICATION;
import static com.android.SdkConstants.TAG_PERMISSION;
@@ -203,7 +204,7 @@ public class ManifestOrderDetector extends Detector implements Detector.XmlScann
Severity.WARNING,
ManifestOrderDetector.class,
Scope.MANIFEST_SCOPE).setMoreInfo(
- "http://developer.android.com/reference/android/R.attr.html#allowBackup");
+ "http://developer.android.com/reference/android/R.attr.html#allowBackup");
/** Conflicting permission names */
public static final Issue UNIQUE_PERMISSION = Issue.create(
@@ -225,6 +226,40 @@ public class ManifestOrderDetector extends Detector implements Detector.XmlScann
ManifestOrderDetector.class,
Scope.MANIFEST_SCOPE);
+ /** Using a resource for attributes that do not allow it */
+ public static final Issue SET_VERSION = Issue.create(
+ "MissingVersion", //$NON-NLS-1$
+ "Checks that the application name and version are set",
+
+ "You should define the version information for your application.\n" +
+ "`android:versionCode`: An integer value that represents the version of the " +
+ "application code, relative to other versions.\n" +
+ "\n" +
+ "`android:versionName`: A string value that represents the release version of " +
+ "the application code, as it should be shown to users.",
+
+ Category.CORRECTNESS,
+ 2,
+ Severity.WARNING,
+ ManifestOrderDetector.class,
+ Scope.MANIFEST_SCOPE).setMoreInfo(
+ "http://developer.android.com/tools/publishing/versioning.html#appversioning");
+
+ /** Using a resource for attributes that do not allow it */
+ public static final Issue ILLEGAL_REFERENCE = Issue.create(
+ "IllegalResourceRef", //$NON-NLS-1$
+ "Checks for resource references where only literals are allowed",
+
+ "For the `versionCode` attribute, you have to specify an actual integer " +
+ "literal; you cannot use an indirection with a `@dimen/name` resource. " +
+ "Similarly, the `versionName` attribute should be an actual string, not " +
+ "a string resource url.",
+
+ Category.CORRECTNESS,
+ 8,
+ Severity.WARNING,
+ ManifestOrderDetector.class,
+ Scope.MANIFEST_SCOPE);
/** Constructs a new {@link ManifestOrderDetector} check */
public ManifestOrderDetector() {
@@ -263,6 +298,12 @@ public class ManifestOrderDetector extends Detector implements Detector.XmlScann
@Override
public void afterCheckFile(@NonNull Context context) {
+ XmlContext xmlContext = (XmlContext) context;
+ Element element = xmlContext.document.getDocumentElement();
+ if (element != null) {
+ checkDocumentElement(xmlContext, element);
+ }
+
if (mSeenUsesSdk == 0 && context.isEnabled(USES_SDK)) {
context.report(USES_SDK, Location.create(context.file),
"Manifest should specify a minimum API level with " +
@@ -271,6 +312,29 @@ public class ManifestOrderDetector extends Detector implements Detector.XmlScann
}
}
+ private void checkDocumentElement(XmlContext context, Element element) {
+ Attr codeNode = element.getAttributeNodeNS(ANDROID_URI, "versionCode");//$NON-NLS-1$
+ if (codeNode != null && codeNode.getValue().startsWith(PREFIX_RESOURCE_REF)
+ && context.isEnabled(ILLEGAL_REFERENCE)) {
+ context.report(ILLEGAL_REFERENCE, element, context.getLocation(element),
+ "The android:versionCode cannot be a resource url, it must be "
+ + "a literal integer", null);
+ } else if (codeNode == null && context.isEnabled(SET_VERSION)) {
+ context.report(SET_VERSION, element, context.getLocation(element),
+ "Should set android:versionCode to specify the application version", null);
+ }
+ Attr nameNode = element.getAttributeNodeNS(ANDROID_URI, "versionName");//$NON-NLS-1$
+ if (nameNode != null && nameNode.getValue().startsWith(PREFIX_RESOURCE_REF)
+ && context.isEnabled(ILLEGAL_REFERENCE)) {
+ context.report(ILLEGAL_REFERENCE, element, context.getLocation(element),
+ "The android:versionName cannot be a resource url, it must be "
+ + "a literal string", null);
+ } else if (nameNode == null && context.isEnabled(SET_VERSION)) {
+ context.report(SET_VERSION, element, context.getLocation(element),
+ "Should set android:versionName to specify the application version", null);
+ }
+ }
+
// ---- Implements Detector.XmlScanner ----
@Override
@@ -377,6 +441,14 @@ public class ManifestOrderDetector extends Detector implements Detector.XmlScann
"<uses-sdk> tag should specify a minimum API level with " +
"android:minSdkVersion=\"?\"", null);
}
+ } else {
+ Attr codeNode = element.getAttributeNodeNS(ANDROID_URI, ATTR_MIN_SDK_VERSION);
+ if (codeNode != null && codeNode.getValue().startsWith(PREFIX_RESOURCE_REF)
+ && context.isEnabled(ILLEGAL_REFERENCE)) {
+ context.report(ILLEGAL_REFERENCE, element, context.getLocation(element),
+ "The android:minSdkVersion cannot be a resource url, it must be "
+ + "a literal integer (or string if a preview codename)", null);
+ }
}
if (!element.hasAttributeNS(ANDROID_URI, ATTR_TARGET_SDK_VERSION)) {
@@ -405,8 +477,15 @@ public class ManifestOrderDetector extends Detector implements Detector.XmlScann
// Ignore: AAPT will enforce this.
}
}
- }
+ Attr nameNode = element.getAttributeNodeNS(ANDROID_URI, ATTR_TARGET_SDK_VERSION);
+ if (nameNode != null && nameNode.getValue().startsWith(PREFIX_RESOURCE_REF)
+ && context.isEnabled(ILLEGAL_REFERENCE)) {
+ context.report(ILLEGAL_REFERENCE, element, context.getLocation(element),
+ "The android:targetSdkVersion cannot be a resource url, it must be "
+ + "a literal integer (or string if a preview codename)", null);
+ }
+ }
if (tag.equals(TAG_PERMISSION)) {
Attr nameNode = element.getAttributeNodeNS(ANDROID_URI, ATTR_NAME);
if (nameNode != null) {
@@ -470,7 +549,7 @@ public class ManifestOrderDetector extends Detector implements Detector.XmlScann
private String getPackage(Element element) {
if (mPackage == null) {
- return element.getOwnerDocument().getDocumentElement().getAttribute(ATTR_PACKAGE);
+ mPackage = element.getOwnerDocument().getDocumentElement().getAttribute(ATTR_PACKAGE);
}
return mPackage;