Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* 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.SdkConstants.ANDROID_STRING_PREFIX;
import static com.android.SdkConstants.ANDROID_URI;
import static com.android.SdkConstants.ATTR_BACKGROUND;
import static com.android.SdkConstants.ATTR_ID;
import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_PARENT_LEFT;
import static com.android.SdkConstants.ATTR_LAYOUT_ALIGN_PARENT_RIGHT;
import static com.android.SdkConstants.ATTR_LAYOUT_TO_LEFT_OF;
import static com.android.SdkConstants.ATTR_LAYOUT_TO_RIGHT_OF;
import static com.android.SdkConstants.ATTR_NAME;
import static com.android.SdkConstants.ATTR_ORIENTATION;
import static com.android.SdkConstants.ATTR_STYLE;
import static com.android.SdkConstants.ATTR_TEXT;
import static com.android.SdkConstants.BUTTON;
import static com.android.SdkConstants.LINEAR_LAYOUT;
import static com.android.SdkConstants.RELATIVE_LAYOUT;
import static com.android.SdkConstants.STRING_PREFIX;
import static com.android.SdkConstants.TABLE_ROW;
import static com.android.SdkConstants.TAG_STRING;
import static com.android.SdkConstants.VALUE_SELECTABLE_ITEM_BACKGROUND;
import static com.android.SdkConstants.VALUE_TRUE;
import static com.android.SdkConstants.VALUE_VERTICAL;
import com.android.SdkConstants;
import com.android.annotations.NonNull;
import com.android.resources.ResourceFolderType;
import com.android.tools.lint.detector.api.Category;
import com.android.tools.lint.detector.api.Context;
import com.android.tools.lint.detector.api.Implementation;
import com.android.tools.lint.detector.api.Issue;
import com.android.tools.lint.detector.api.LintUtils;
import com.android.tools.lint.detector.api.Location;
import com.android.tools.lint.detector.api.ResourceXmlDetector;
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.Node;
import org.w3c.dom.NodeList;
import java.io.File;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Check which looks at the order of buttons in dialogs and makes sure that
* "the dismissive action of a dialog is always on the left whereas the affirmative actions
* are on the right."
*
* This only looks for the affirmative and dismissive actions named "OK" and "Cancel";
* "Cancel" usually works, but the affirmative action often has many other names -- "Done",
* "Send", "Go", etc.
*
* TODO: Perhaps we should look for Yes/No dialogs and suggested they be rephrased as
* Cancel/OK dialogs? Similarly, consider "Abort" a synonym for "Cancel" ?
*/
public class ButtonDetector extends ResourceXmlDetector {
/** Name of cancel value ("Cancel") */
private static final String CANCEL_LABEL = "Cancel";
/** Name of OK value ("Cancel") */
private static final String OK_LABEL = "OK";
/** Name of Back value ("Back") */
private static final String BACK_LABEL = "Back";
/** Yes */
private static final String YES_LABEL = "Yes";
/** No */
private static final String NO_LABEL = "No";
/** Layout text attribute reference to {@code @android:string/ok} */
private static final String ANDROID_OK_RESOURCE =
ANDROID_STRING_PREFIX + "ok"; //$NON-NLS-1$
/** Layout text attribute reference to {@code @android:string/cancel} */
private static final String ANDROID_CANCEL_RESOURCE =
ANDROID_STRING_PREFIX + "cancel"; //$NON-NLS-1$
/** Layout text attribute reference to {@code @android:string/yes} */
private static final String ANDROID_YES_RESOURCE =
ANDROID_STRING_PREFIX + "yes"; //$NON-NLS-1$
/** Layout text attribute reference to {@code @android:string/no} */
private static final String ANDROID_NO_RESOURCE =
ANDROID_STRING_PREFIX + "no"; //$NON-NLS-1$
private static final Implementation IMPLEMENTATION = new Implementation(
ButtonDetector.class,
Scope.RESOURCE_FILE_SCOPE);
/** The main issue discovered by this detector */
public static final Issue ORDER = Issue.create(
"ButtonOrder", //$NON-NLS-1$
"Button order",
"According to the Android Design Guide,\n" +
"\n" +
"\"Action buttons are typically Cancel and/or OK, with OK indicating the preferred " +
"or most likely action. However, if the options consist of specific actions such " +
"as Close or Wait rather than a confirmation or cancellation of the action " +
"described in the content, then all the buttons should be active verbs. As a rule, " +
"the dismissive action of a dialog is always on the left whereas the affirmative " +
"actions are on the right.\"\n" +
"\n" +
"This check looks for button bars and buttons which look like cancel buttons, " +
"and makes sure that these are on the left.",
Category.USABILITY,
8,
Severity.WARNING,
IMPLEMENTATION)
.addMoreInfo(
"http://developer.android.com/design/building-blocks/dialogs.html"); //$NON-NLS-1$
/** The main issue discovered by this detector */
public static final Issue STYLE = Issue.create(
"ButtonStyle", //$NON-NLS-1$
"Button should be borderless",
"Button bars typically use a borderless style for the buttons. Set the " +
"`style=\"?android:attr/buttonBarButtonStyle\"` attribute " +
"on each of the buttons, and set `style=\"?android:attr/buttonBarStyle\"` on " +
"the parent layout",
Category.USABILITY,
5,
Severity.WARNING,
IMPLEMENTATION)
.addMoreInfo(
"http://developer.android.com/design/building-blocks/buttons.html"); //$NON-NLS-1$
/** The main issue discovered by this detector */
public static final Issue BACK_BUTTON = Issue.create(
"BackButton", //$NON-NLS-1$
"Back button",
// TODO: Look for ">" as label suffixes as well
"According to the Android Design Guide,\n" +
"\n" +
"\"Other platforms use an explicit back button with label to allow the user " +
"to navigate up the application's hierarchy. Instead, Android uses the main " +
"action bar's app icon for hierarchical navigation and the navigation bar's " +
"back button for temporal navigation.\"" +
"\n" +
"This check is not very sophisticated (it just looks for buttons with the " +
"label \"Back\"), so it is disabled by default to not trigger on common " +
"scenarios like pairs of Back/Next buttons to paginate through screens.",
Category.USABILITY,
6,
Severity.WARNING,
IMPLEMENTATION)
.setEnabledByDefault(false)
.addMoreInfo(
"http://developer.android.com/design/patterns/pure-android.html"); //$NON-NLS-1$
/** The main issue discovered by this detector */
public static final Issue CASE = Issue.create(
"ButtonCase", //$NON-NLS-1$
"Cancel/OK dialog button capitalization",
"The standard capitalization for OK/Cancel dialogs is \"OK\" and \"Cancel\". " +
"To ensure that your dialogs use the standard strings, you can use " +
"the resource strings @android:string/ok and @android:string/cancel.",
Category.USABILITY,
2,
Severity.WARNING,
IMPLEMENTATION);
/** Set of resource names whose value was either OK or Cancel */
private Set mApplicableResources;
/**
* Map of resource names we'd like resolved into strings in phase 2. The
* values should be filled in with the actual string contents.
*/
private Map mKeyToLabel;
/**
* Set of elements we've already warned about. If we've already complained
* about a cancel button, don't also report the OK button (since it's listed
* for the warnings on OK buttons).
*/
private Set mIgnore;
/** Constructs a new {@link ButtonDetector} */
public ButtonDetector() {
}
@NonNull
@Override
public Speed getSpeed() {
return Speed.FAST;
}
@Override
public Collection getApplicableElements() {
return Arrays.asList(BUTTON, TAG_STRING);
}
@Override
public boolean appliesTo(@NonNull ResourceFolderType folderType) {
return folderType == ResourceFolderType.LAYOUT || folderType == ResourceFolderType.VALUES;
}
@Override
public void afterCheckProject(@NonNull Context context) {
int phase = context.getPhase();
if (phase == 1 && mApplicableResources != null) {
// We found resources for the string "Cancel"; perform a second pass
// where we check layout text attributes against these strings.
context.getDriver().requestRepeat(this, Scope.RESOURCE_FILE_SCOPE);
}
}
private static String stripLabel(String text) {
text = text.trim();
if (text.length() > 2
&& (text.charAt(0) == '"' || text.charAt(0) == '\'')
&& (text.charAt(0) == text.charAt(text.length() - 1))) {
text = text.substring(1, text.length() - 1);
}
return text;
}
@Override
public void visitElement(@NonNull XmlContext context, @NonNull Element element) {
// This detector works in two passes.
// In pass 1, it looks in layout files for hardcoded strings of "Cancel", or
// references to @string/cancel or @android:string/cancel.
// It also looks in values/ files for strings whose value is "Cancel",
// and if found, stores the corresponding keys in a map. (This is necessary
// since value files are processed after layout files).
// Then, if at the end of phase 1 any "Cancel" string resources were
// found in the value files, then it requests a *second* phase,
// where it looks only for