Merge change Ic8fe0b36 into eclair
* changes: Add 3 more rules to layoutopt/uix: - InefficientWeight - NestedScrollingWidgets - TooManyChildren
This commit is contained in:
@@ -62,6 +62,15 @@ public class LayoutAnalysis {
|
||||
mName = name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an issue to the layout analysis.
|
||||
*
|
||||
* @param issue The issue to add.
|
||||
*/
|
||||
public void addIssue(Issue issue) {
|
||||
mIssues.add(issue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an issue to the layout analysis.
|
||||
*
|
||||
@@ -116,7 +125,12 @@ public class LayoutAnalysis {
|
||||
private final String mDescription;
|
||||
private final LayoutNode mNode;
|
||||
|
||||
Issue(String description) {
|
||||
/**
|
||||
* Creates a new issue with the specified description.
|
||||
*
|
||||
* @param description The description of the issue.
|
||||
*/
|
||||
public Issue(String description) {
|
||||
mNode = null;
|
||||
if (description == null) {
|
||||
throw new IllegalArgumentException("The description must be non-null");
|
||||
@@ -124,6 +138,12 @@ public class LayoutAnalysis {
|
||||
mDescription = description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new issue with the specified description.
|
||||
*
|
||||
* @param node The node in which the issue was found.
|
||||
* @param description The description of the issue.
|
||||
*/
|
||||
public Issue(LayoutNode node, String description) {
|
||||
mNode = node;
|
||||
if (description == null) {
|
||||
|
||||
@@ -20,16 +20,30 @@ import com.android.layoutopt.uix.LayoutAnalysis;
|
||||
import com.android.layoutopt.uix.LayoutNode;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import groovy.lang.GString;
|
||||
import groovy.xml.dom.DOMCategory;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Support class for Groovy rules. This class adds new Groovy capabilities
|
||||
* to {@link com.android.layoutopt.uix.LayoutAnalysis} and {@link org.w3c.dom.Node}.
|
||||
*/
|
||||
public class LayoutAnalysisCategory {
|
||||
public static List<Node> all(Element element) {
|
||||
NodeList list = DOMCategory.depthFirst(element);
|
||||
int count = list.getLength();
|
||||
List<Node> nodes = new ArrayList<Node>(count - 1);
|
||||
for (int i = 1; i < count; i++) {
|
||||
nodes.add(list.item(i));
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* xmlNode.isRoot()
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
// Rule: InefficientWeight
|
||||
//
|
||||
// Description: Checks whether a layout_weight is declared inefficiently.
|
||||
//
|
||||
// Conditions:
|
||||
// - The node has a LinearLayout parent
|
||||
// - The node is the only sibling with a weight
|
||||
// - The node has a height/width != 0
|
||||
|
||||
def parent = xml.'..'
|
||||
if (parent.is("LinearLayout") && xml.'@android:layout_weight' &&
|
||||
parent.'*'.findAll{ it.'@android:layout_weight' }.size() == 1) {
|
||||
def dimension = parent.'@android:orientation' == "vertical" ?
|
||||
"android:layout_height" : "android:layout_width"
|
||||
if (xml."@${dimension}"[0] != 0) {
|
||||
analysis << [node: node, description: "Use an ${dimension} of 0dip instead of " +
|
||||
"${xml."@${dimension}"} for better performance"]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// Rule: NestedScrollingWidgets
|
||||
//
|
||||
// Description: Checks whether a scrolling widget has nested scrolling widgets.
|
||||
//
|
||||
// Conditions:
|
||||
// - The node is a scrolling widget
|
||||
// - The node has a descendant who is also a scrolling widget
|
||||
|
||||
def widgets = ["ScrollView", "ListView", "GridView"]
|
||||
if (xml.name() in widgets && xml.all().any{ it.name() in widgets }) {
|
||||
analysis << [node: node, description: "The vertically scrolling ${xml.name()} should " +
|
||||
"not contain another vertically scrolling widget"]
|
||||
}
|
||||
|
||||
widgets = ["HorizontalScrollView", "Gallery"]
|
||||
if (xml.name() in widgets && xml.all().any{ it.name() in widgets }) {
|
||||
analysis << [node: node, description: "The horizontally scrolling ${xml.name()} should " +
|
||||
"not contain another horizontally scrolling widget"]
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
// Rule: TooManyChildren
|
||||
//
|
||||
// Description: Checks whether the layout has too many children.
|
||||
//
|
||||
// Conditions:
|
||||
// - The layout is a ScrollView and has more than 1 child
|
||||
// - The layout is a list or grid ans has at least 1 child
|
||||
|
||||
if (xml.name() in ["ScrollView", "HorizontalScrollView"] && xml.'*'.size() > 1) {
|
||||
analysis << [node: node, description: "A scroll view can have only one child"]
|
||||
}
|
||||
|
||||
if (xml.name() in ["ListView", "GridView"] && xml.'*'.size() > 0) {
|
||||
analysis << [node: node, description: "A list/grid should have no children declared in XML"]
|
||||
}
|
||||
@@ -8,8 +8,8 @@
|
||||
// - The node has two children, ImageView and TextView
|
||||
// - The ImageView does not have a weight
|
||||
|
||||
if (xml.is("LinearLayout") && xml['*'].size() == 2 && xml.'TextView'.size() == 1 &&
|
||||
xml.'ImageView'.size() == 1 && !xml.'ImageView'.'@android:layout_weight') {
|
||||
if (xml.is("LinearLayout") && xml.'*'.size() == 2 && xml.'TextView'.size() == 1 &&
|
||||
xml.'ImageView'.size() == 1 && !xml.'ImageView'[0].'@android:layout_weight') {
|
||||
analysis << [node: node, description: "This tag and its children can be replaced by one " +
|
||||
"<TextView/> and a compound drawable for the image"]
|
||||
"<TextView/> and a compound drawable"]
|
||||
}
|
||||
|
||||
@@ -5,13 +5,15 @@
|
||||
// Conditions:
|
||||
// - The node has children
|
||||
// - The node does not have siblings
|
||||
// - The node's parent is not a scroll view (horizontal or vertical)
|
||||
// - The node does not have a background or its parent does not have a
|
||||
// background or neither the node and its parent have a background
|
||||
// - The parent is not a <merge/>
|
||||
|
||||
if (!xml.isRoot() && xml['..'].name() != "merge" && xml['..']['*'].size() == 1 &&
|
||||
xml['*'].size() > 0 && ((xml.'@android:background' || xml['..'].'@android:background') ||
|
||||
(!xml.'@android:background' && !xml['..'].'@android:background'))) {
|
||||
if (!xml.isRoot() && !(xml['..'].name() in ["ScrollView", "HorizontalScrollView"]) &&
|
||||
xml['..']['*'].size() == 1 && xml['*'].size() > 0 && ((xml.'@android:background' ||
|
||||
xml['..'].'@android:background') || (!xml.'@android:background' &&
|
||||
!xml['..'].'@android:background'))) {
|
||||
analysis << [node: node, description: "This ${xml.name()} layout or " +
|
||||
"its ${xml['..'].name()} parent is " +
|
||||
"${xml['..'].'@android:id' ? "possibly useless" : "useless"}"]
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<FrameLayout
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
@@ -19,5 +15,3 @@
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
13
tools/layoutopt/samples/has_children.xml
Normal file
13
tools/layoutopt/samples/has_children.xml
Normal file
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<ListView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<ListView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent" />
|
||||
|
||||
</ListView>
|
||||
29
tools/layoutopt/samples/inefficient_weight.xml
Normal file
29
tools/layoutopt/samples/inefficient_weight.xml
Normal file
@@ -0,0 +1,29 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<Button
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1.0" />
|
||||
|
||||
<LinearLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
|
||||
android:orientation="vertical">
|
||||
|
||||
<Button
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1.0" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
19
tools/layoutopt/samples/scrolling.xml
Normal file
19
tools/layoutopt/samples/scrolling.xml
Normal file
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<ScrollView
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<ListView
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
Reference in New Issue
Block a user