blob: b14e58b1d21f764e6bf1f0f7429366d0a3f0b24e [file] [log] [blame]
/*
* Copyright (C) 2011 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.SdkConstants.ANDROID_URI
import com.android.SdkConstants.ATTR_CONTENT_DESCRIPTION
import com.android.SdkConstants.ATTR_HINT
import com.android.SdkConstants.ATTR_LABEL
import com.android.SdkConstants.ATTR_PROMPT
import com.android.SdkConstants.ATTR_TEXT
import com.android.SdkConstants.ATTR_TITLE
import com.android.resources.ResourceFolderType
import com.android.tools.lint.checks.RestrictionsDetector.Companion.ATTR_DESCRIPTION
import com.android.tools.lint.checks.RestrictionsDetector.Companion.TAG_RESTRICTIONS
import com.android.tools.lint.detector.api.Category
import com.android.tools.lint.detector.api.Implementation
import com.android.tools.lint.detector.api.Issue
import com.android.tools.lint.detector.api.LayoutDetector
import com.android.tools.lint.detector.api.Scope
import com.android.tools.lint.detector.api.Severity
import com.android.tools.lint.detector.api.XmlContext
import org.w3c.dom.Attr
import java.util.Arrays
/**
* Check which looks at the children of ScrollViews and ensures that they fill/match the parent
* width instead of setting wrap_content.
*
*
* TODO: Consider looking at the localization="suggested" attribute in the platform attrs.xml to
* catch future recommended attributes.
*/
class HardcodedValuesDetector : LayoutDetector() {
override fun getApplicableAttributes(): Collection<String>? {
return Arrays.asList(
// Layouts
ATTR_TEXT,
ATTR_CONTENT_DESCRIPTION,
ATTR_HINT,
ATTR_LABEL,
ATTR_PROMPT,
"textOn",
"textOff",
// Menus
ATTR_TITLE,
// App restrictions
ATTR_DESCRIPTION
)
}
override fun appliesTo(folderType: ResourceFolderType): Boolean {
return (folderType == ResourceFolderType.LAYOUT ||
folderType == ResourceFolderType.MENU ||
folderType == ResourceFolderType.XML)
}
override fun visitAttribute(context: XmlContext, attribute: Attr) {
val value = attribute.value
if (!value.isEmpty() && value[0] != '@' && value[0] != '?') {
// Make sure this is really one of the android: attributes
if (ANDROID_URI != attribute.namespaceURI) {
return
}
// Filter out a few special cases:
if (value == "Hello World!") {
// This is the default text in new templates. Users are unlikely to
// leave this in, so let's not add warnings in the editor as their
// welcome to Android development greeting.
return
}
if (value == "Large Text" ||
value == "Medium Text" ||
value == "Small Text" ||
value.startsWith("New ") && (value == "New Text" || value == "New " + attribute.ownerElement.tagName)
) {
// The layout editor initially places the label "New Button", "New TextView",
// etc on widgets dropped on the layout editor. Again, users are unlikely
// to leave it that way, so let's not flag it until they change it.
return
}
// In XML folders, currently only checking application restriction files
// (since in general the res/xml folder can contain arbitrary XML content
// interpreted by the app)
if (context.resourceFolderType == ResourceFolderType.XML) {
val tagName = attribute.ownerDocument.documentElement.tagName
if (tagName != TAG_RESTRICTIONS) {
return
}
}
context.report(
ISSUE,
attribute,
context.getLocation(attribute),
String.format(
"Hardcoded string \"%1\$s\", should use `@string` resource", value
)
)
}
}
companion object {
// TODO: Add additional issues here, such as hardcoded colors, hardcoded sizes, etc
/** The main issue discovered by this detector */
@JvmField
val ISSUE = Issue.create(
id = "HardcodedText",
briefDescription = "Hardcoded text",
explanation = """
Hardcoding text attributes directly in layout files is bad for several reasons:
* When creating configuration variations (for example for landscape or \
portrait) you have to repeat the actual text (and keep it up to date when \
making changes)
* The application cannot be translated to other languages by just adding new \
translations for existing string resources.
There are quickfixes to automatically extract this hardcoded string into a \
resource lookup.
""",
category = Category.I18N,
priority = 5,
severity = Severity.WARNING,
implementation = Implementation(
HardcodedValuesDetector::class.java,
Scope.RESOURCE_FILE_SCOPE
)
)
}
}