blob: 4c0a56a3a55c80546989520e7c03ad6c37dc39ef [file] [log] [blame]
/*
* Copyright (C) 2015 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 AppIndexingApiDetectorTest extends AbstractCheckTest {
@Override
protected Detector getDetector() {
return new AppIndexingApiDetector();
}
public void testOk() throws Exception {
assertEquals("No warnings.",
lintProject(xml("AndroidManifest.xml", ""
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.helloworld\" >\n"
+ "\n"
+ " <application\n"
+ " android:allowBackup=\"true\"\n"
+ " android:icon=\"@mipmap/ic_launcher\"\n"
+ " android:label=\"@string/app_name\"\n"
+ " android:theme=\"@style/AppTheme\" >\n"
+ " <activity\n"
+ " android:name=\".FullscreenActivity\"\n"
+ " android:configChanges=\"orientation|keyboardHidden|screenSize\"\n"
+ " android:label=\"@string/title_activity_fullscreen\"\n"
+ " android:theme=\"@style/FullscreenTheme\" >\n"
+ " <intent-filter android:label=\"@string/title_activity_fullscreen\">\n"
+ " <action android:name=\"android.intent.action.VIEW\" />\n"
+ " <data android:scheme=\"http\"\n"
+ " android:host=\"example.com\"\n"
+ " android:pathPrefix=\"/gizmos\" />\n"
+ " <category android:name=\"android.intent.category.DEFAULT\" />\n"
+ " <category android:name=\"android.intent.category.BROWSABLE\" />\n"
+ " </intent-filter>\n"
+ " </activity>\n"
+ " </application>\n"
+ "\n"
+ "</manifest>\n")));
}
public void testDataMissing() throws Exception {
assertEquals(""
+ "AndroidManifest.xml:15: Error: Missing data node? [AppIndexingError]\n"
+ " <intent-filter android:label=\"@string/title_activity_fullscreen\">\n"
+ " ^\n"
+ "1 errors, 0 warnings\n",
lintProject(xml("AndroidManifest.xml", ""
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.helloworld\" >\n"
+ "\n"
+ " <application\n"
+ " android:allowBackup=\"true\"\n"
+ " android:icon=\"@mipmap/ic_launcher\"\n"
+ " android:label=\"@string/app_name\"\n"
+ " android:theme=\"@style/AppTheme\" >\n"
+ " <activity\n"
+ " android:name=\".FullscreenActivity\"\n"
+ " android:configChanges=\"orientation|keyboardHidden|screenSize\"\n"
+ " android:label=\"@string/title_activity_fullscreen\"\n"
+ " android:theme=\"@style/FullscreenTheme\" >\n"
+ " <intent-filter android:label=\"@string/title_activity_fullscreen\">\n"
+ " <action android:name=\"android.intent.action.VIEW\" />\n"
+ " <category android:name=\"android.intent.category.DEFAULT\" />\n"
+ " <category android:name=\"android.intent.category.BROWSABLE\" />\n"
+ " </intent-filter>\n"
+ " </activity>\n"
+ " </application>\n"
+ "\n"
+ "</manifest>\n")));
}
public void testNoUrl() throws Exception {
assertEquals(""
+ "AndroidManifest.xml:17: Error: Missing URL for the intent filter? [AppIndexingError]\n"
+ " <data />\n"
+ " ~~~~~~~~\n"
+ "1 errors, 0 warnings\n",
lintProject(xml("AndroidManifest.xml", ""
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.helloworld\" >\n"
+ "\n"
+ " <application\n"
+ " android:allowBackup=\"true\"\n"
+ " android:icon=\"@mipmap/ic_launcher\"\n"
+ " android:label=\"@string/app_name\"\n"
+ " android:theme=\"@style/AppTheme\" >\n"
+ " <activity\n"
+ " android:name=\".FullscreenActivity\"\n"
+ " android:configChanges=\"orientation|keyboardHidden|screenSize\"\n"
+ " android:label=\"@string/title_activity_fullscreen\"\n"
+ " android:theme=\"@style/FullscreenTheme\" >\n"
+ " <intent-filter android:label=\"@string/title_activity_fullscreen\">\n"
+ " <action android:name=\"android.intent.action.VIEW\" />\n"
+ " <data />\n"
+ " <category android:name=\"android.intent.category.DEFAULT\" />\n"
+ " <category android:name=\"android.intent.category.BROWSABLE\" />\n"
+ " </intent-filter>\n"
+ " </activity>\n"
+ " </application>\n"
+ "\n"
+ "</manifest>\n")));
}
public void testMimeType() throws Exception {
assertEquals("No warnings.",
lintProject(xml("AndroidManifest.xml", ""
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.helloworld\" >\n"
+ "\n"
+ " <application\n"
+ " android:allowBackup=\"true\"\n"
+ " android:icon=\"@mipmap/ic_launcher\"\n"
+ " android:label=\"@string/app_name\"\n"
+ " android:theme=\"@style/AppTheme\" >\n"
+ " <activity\n"
+ " android:name=\".FullscreenActivity\"\n"
+ " android:configChanges=\"orientation|keyboardHidden|screenSize\"\n"
+ " android:label=\"@string/title_activity_fullscreen\"\n"
+ " android:theme=\"@style/FullscreenTheme\" >\n"
+ " <intent-filter android:label=\"@string/title_activity_fullscreen\">\n"
+ " <action android:name=\"android.intent.action.VIEW\" />\n"
+ " <data android:mimeType=\"mimetype\" /> "
+ " <category android:name=\"android.intent.category.DEFAULT\" />\n"
+ " <category android:name=\"android.intent.category.BROWSABLE\" />\n"
+ " </intent-filter>\n"
+ " </activity>\n"
+ " </application>\n"
+ "\n"
+ "</manifest>\n")));
}
public void testNoActivity() throws Exception {
assertEquals(
"No warnings.",
lintProject(xml("AndroidManifest.xml", ""
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.helloworld\" >\n"
+ "\n"
+ " <application\n"
+ " android:allowBackup=\"true\"\n"
+ " android:icon=\"@mipmap/ic_launcher\"\n"
+ " android:label=\"@string/app_name\"\n"
+ " android:theme=\"@style/AppTheme\" >\n"
+ " </application>\n"
+ "\n"
+ "</manifest>\n")));
}
public void testNotBrowsable() throws Exception {
assertEquals(""
+ "AndroidManifest.xml:25: Warning: Activity supporting ACTION_VIEW is not set as BROWSABLE [AppIndexingWarning]\n"
+ " <intent-filter android:label=\"@string/title_activity_fullscreen\">\n"
+ " ^\n"
+ "0 errors, 1 warnings\n",
lintProject(xml("AndroidManifest.xml", ""
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.helloworld\" >\n"
+ "\n"
+ " <application\n"
+ " android:allowBackup=\"true\"\n"
+ " android:icon=\"@mipmap/ic_launcher\"\n"
+ " android:label=\"@string/app_name\"\n"
+ " android:theme=\"@style/AppTheme\" >\n"
+ " <activity\n"
+ " android:name=\".MainActivity\"\n"
+ " android:label=\"@string/app_name\" >\n"
+ " <intent-filter>\n"
+ " <action android:name=\"android.intent.action.MAIN\" />\n"
+ "\n"
+ " <category android:name=\"android.intent.category.LAUNCHER\" />\n"
+ " </intent-filter>\n"
+ " </activity>\n"
+ "\n"
+ " <activity\n"
+ " android:name=\".FullscreenActivity\"\n"
+ " android:configChanges=\"orientation|keyboardHidden|screenSize\"\n"
+ " android:label=\"@string/title_activity_fullscreen\"\n"
+ " android:theme=\"@style/FullscreenTheme\" >\n"
+ " <intent-filter android:label=\"@string/title_activity_fullscreen\">\n"
+ " <action android:name=\"android.intent.action.VIEW\" />\n"
+ " <data android:scheme=\"http\"\n"
+ " android:host=\"example.com\"\n"
+ " android:pathPrefix=\"/gizmos\" />\n"
+ " <category android:name=\"android.intent.category.DEFAULT\" />\n"
+ " </intent-filter>\n"
+ " </activity>\n"
+ " </application>\n"
+ "\n"
+ "</manifest>\n")));
}
public void testWrongPathPrefix() throws Exception {
assertEquals(""
+ "AndroidManifest.xml:19: Error: android:pathPrefix attribute should start with '/', but it is : gizmos [AppIndexingError]\n"
+ " android:pathPrefix=\"gizmos\" />\n"
+ " ~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"
+ "1 errors, 0 warnings\n",
lintProject(xml("AndroidManifest.xml", ""
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.helloworld\" >\n"
+ "\n"
+ " <application\n"
+ " android:allowBackup=\"true\"\n"
+ " android:icon=\"@mipmap/ic_launcher\"\n"
+ " android:label=\"@string/app_name\"\n"
+ " android:theme=\"@style/AppTheme\" >\n"
+ " <activity\n"
+ " android:name=\".FullscreenActivity\"\n"
+ " android:configChanges=\"orientation|keyboardHidden|screenSize\"\n"
+ " android:label=\"@string/title_activity_fullscreen\"\n"
+ " android:theme=\"@style/FullscreenTheme\" >\n"
+ " <intent-filter android:label=\"@string/title_activity_fullscreen\">\n"
+ " <action android:name=\"android.intent.action.VIEW\" />\n"
+ " <data android:scheme=\"http\"\n"
+ " android:host=\"example.com\"\n"
+ " android:pathPrefix=\"gizmos\" />\n"
+ " <category android:name=\"android.intent.category.DEFAULT\" />\n"
+ " <category android:name=\"android.intent.category.BROWSABLE\" />\n"
+ " </intent-filter>\n"
+ " </activity>\n"
+ " </application>\n"
+ "\n"
+ "</manifest>\n")));
}
public void testWrongPort() throws Exception {
assertEquals(""
+ "AndroidManifest.xml:19: Error: android:port is not a legal number [AppIndexingError]\n"
+ " android:port=\"ABCD\"\n"
+ " ~~~~~~~~~~~~~~~~~~~\n"
+ "1 errors, 0 warnings\n",
lintProject(xml("AndroidManifest.xml", ""
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.helloworld\" >\n"
+ "\n"
+ " <application\n"
+ " android:allowBackup=\"true\"\n"
+ " android:icon=\"@mipmap/ic_launcher\"\n"
+ " android:label=\"@string/app_name\"\n"
+ " android:theme=\"@style/AppTheme\" >\n"
+ " <activity\n"
+ " android:name=\".FullscreenActivity\"\n"
+ " android:configChanges=\"orientation|keyboardHidden|screenSize\"\n"
+ " android:label=\"@string/title_activity_fullscreen\"\n"
+ " android:theme=\"@style/FullscreenTheme\" >\n"
+ " <intent-filter android:label=\"@string/title_activity_fullscreen\">\n"
+ " <action android:name=\"android.intent.action.VIEW\" />\n"
+ " <data android:scheme=\"http\"\n"
+ " android:host=\"example.com\"\n"
+ " android:port=\"ABCD\"\n"
+ " android:pathPrefix=\"/gizmos\" />\n"
+ " <category android:name=\"android.intent.category.DEFAULT\" />\n"
+ " <category android:name=\"android.intent.category.BROWSABLE\" />\n"
+ " </intent-filter>\n"
+ " </activity>\n"
+ " </application>\n"
+ "\n"
+ "</manifest>\n")));
}
public void testSchemeAndHostMissing() throws Exception {
assertEquals(""
+ "AndroidManifest.xml:17: Error: Missing URL for the intent filter? [AppIndexingError]\n"
+ " <data android:pathPrefix=\"/gizmos\" />\n"
+ " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"
+ "AndroidManifest.xml:17: Error: android:host missing [AppIndexingError]\n"
+ " <data android:pathPrefix=\"/gizmos\" />\n"
+ " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"
+ "AndroidManifest.xml:17: Error: android:scheme missing [AppIndexingError]\n"
+ " <data android:pathPrefix=\"/gizmos\" />\n"
+ " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"
+ "3 errors, 0 warnings\n",
lintProject(xml("AndroidManifest.xml", ""
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.helloworld\" >\n"
+ "\n"
+ " <application\n"
+ " android:allowBackup=\"true\"\n"
+ " android:icon=\"@mipmap/ic_launcher\"\n"
+ " android:label=\"@string/app_name\"\n"
+ " android:theme=\"@style/AppTheme\" >\n"
+ " <activity\n"
+ " android:name=\".FullscreenActivity\"\n"
+ " android:configChanges=\"orientation|keyboardHidden|screenSize\"\n"
+ " android:label=\"@string/title_activity_fullscreen\"\n"
+ " android:theme=\"@style/FullscreenTheme\" >\n"
+ " <intent-filter android:label=\"@string/title_activity_fullscreen\">\n"
+ " <action android:name=\"android.intent.action.VIEW\" />\n"
+ " <data android:pathPrefix=\"/gizmos\" />\n"
+ " <category android:name=\"android.intent.category.DEFAULT\" />\n"
+ " <category android:name=\"android.intent.category.BROWSABLE\" />\n"
+ " </intent-filter>\n"
+ " </activity>\n"
+ " </application>\n"
+ "\n"
+ "</manifest>\n")));
}
public void testMultiData() throws Exception {
assertEquals("No warnings.",
lintProject(xml("AndroidManifest.xml", ""
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.helloworld\" >\n"
+ "\n"
+ " <application\n"
+ " android:allowBackup=\"true\"\n"
+ " android:icon=\"@mipmap/ic_launcher\"\n"
+ " android:label=\"@string/app_name\"\n"
+ " android:theme=\"@style/AppTheme\" >\n"
+ " <activity\n"
+ " android:name=\".FullscreenActivity\"\n"
+ " android:configChanges=\"orientation|keyboardHidden|screenSize\"\n"
+ " android:label=\"@string/title_activity_fullscreen\"\n"
+ " android:theme=\"@style/FullscreenTheme\" >\n"
+ " <intent-filter android:label=\"@string/title_activity_fullscreen\">\n"
+ " <action android:name=\"android.intent.action.VIEW\" />\n"
+ " <data android:scheme=\"http\" />\n"
+ " <data android:host=\"example.com\" />\n"
+ " <data android:pathPrefix=\"/gizmos\" />\n"
+ " <category android:name=\"android.intent.category.DEFAULT\" />\n"
+ " <category android:name=\"android.intent.category.BROWSABLE\" />\n"
+ " </intent-filter>\n"
+ " </activity>\n"
+ " </application>\n"
+ "\n"
+ "</manifest>\n")));
}
public void testMultiIntent() throws Exception {
assertEquals("No warnings.",
lintProject(xml("AndroidManifest.xml", ""
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.helloworld\" >\n"
+ "\n"
+ " <application\n"
+ " android:allowBackup=\"true\"\n"
+ " android:icon=\"@mipmap/ic_launcher\"\n"
+ " android:label=\"@string/app_name\"\n"
+ " android:theme=\"@style/AppTheme\" >\n"
+ " <activity\n"
+ " android:name=\".FullscreenActivity\"\n"
+ " android:configChanges=\"orientation|keyboardHidden|screenSize\"\n"
+ " android:label=\"@string/title_activity_fullscreen\"\n"
+ " android:theme=\"@style/FullscreenTheme\" >\n"
+ " <intent-filter>\n"
+ " <action android:name=\"android.intent.action.MAIN\" />\n"
+ " <category android:name=\"android.intent.category.LAUNCHER\" />\n"
+ " </intent-filter>"
+ " <intent-filter android:label=\"@string/title_activity_fullscreen\">\n"
+ " <action android:name=\"android.intent.action.VIEW\" />\n"
+ " <data android:scheme=\"http\"\n"
+ " android:host=\"example.com\"\n"
+ " android:pathPrefix=\"/gizmos\" />\n"
+ " <category android:name=\"android.intent.category.DEFAULT\" />\n"
+ " <category android:name=\"android.intent.category.BROWSABLE\" />\n"
+ " </intent-filter>\n"
+ " </activity>\n"
+ " </application>\n"
+ "\n"
+ "</manifest>\n")));
}
public void testMultiIntentWithError() throws Exception {
assertEquals(""
+ "AndroidManifest.xml:20: Error: android:host missing [AppIndexingError]\n"
+ " <data android:scheme=\"http\"\n"
+ " ^\n"
+ "1 errors, 0 warnings\n",
lintProject(xml("AndroidManifest.xml", ""
+ "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"
+ "<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"
+ " package=\"com.example.helloworld\" >\n"
+ "\n"
+ " <application\n"
+ " android:allowBackup=\"true\"\n"
+ " android:icon=\"@mipmap/ic_launcher\"\n"
+ " android:label=\"@string/app_name\"\n"
+ " android:theme=\"@style/AppTheme\" >\n"
+ " <activity\n"
+ " android:name=\".FullscreenActivity\"\n"
+ " android:configChanges=\"orientation|keyboardHidden|screenSize\"\n"
+ " android:label=\"@string/title_activity_fullscreen\"\n"
+ " android:theme=\"@style/FullscreenTheme\" >\n"
+ " <intent-filter>\n"
+ " <action android:name=\"android.intent.action.MAIN\" />\n"
+ " <category android:name=\"android.intent.category.LAUNCHER\" />\n"
+ " </intent-filter>"
+ " <intent-filter android:label=\"@string/title_activity_fullscreen\">\n"
+ " <action android:name=\"android.intent.action.VIEW\" />\n"
+ " <data android:scheme=\"http\"\n"
+ " android:pathPrefix=\"/gizmos\" />\n"
+ " <category android:name=\"android.intent.category.DEFAULT\" />\n"
+ " <category android:name=\"android.intent.category.BROWSABLE\" />\n"
+ " </intent-filter>\n"
+ " </activity>\n"
+ " </application>\n"
+ "\n"
+ "</manifest>\n")));
}
public void testOkWithResource() throws Exception {
assertEquals("No warnings.",
lintProjectIncrementally(
"AndroidManifest.xml",
"appindexing_manifest.xml=>AndroidManifest.xml",
"res/values/appindexing_strings.xml"));
}
public void testWrongWithResource() throws Exception {
assertEquals("" + "AndroidManifest.xml:18: Error: android:pathPrefix attribute should start with '/', but it is : pathprefix [AppIndexingError]\n"
+ " android:pathPrefix=\"@string/path_prefix\"\n"
+ " ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"
+ "AndroidManifest.xml:19: Error: android:port is not a legal number [AppIndexingError]\n"
+ " android:port=\"@string/port\"/>\n"
+ " ~~~~~~~~~~~~~~~~~~~~~~~~~~~\n"
+ "2 errors, 0 warnings\n",
lintProjectIncrementally(
"AndroidManifest.xml",
"appindexing_manifest.xml=>AndroidManifest.xml",
"res/values/appindexing_wrong_strings.xml"));
}
}