diff options
260 files changed, 3260 insertions, 3297 deletions
diff --git a/anttasks/src/com/android/ant/AaptExecTask.java b/anttasks/src/com/android/ant/AaptExecTask.java index 2b57277..c96f7d0 100644 --- a/anttasks/src/com/android/ant/AaptExecTask.java +++ b/anttasks/src/com/android/ant/AaptExecTask.java @@ -97,6 +97,7 @@ public final class AaptExecTask extends SingleDependencyTask { private String mLibraryPackagesRefid; private boolean mNonConstantId; private String mIgnoreAssets; + private String mProguardFile; /** * Input path that ignores the same folders/files that aapt does. @@ -321,6 +322,10 @@ public final class AaptExecTask extends SingleDependencyTask { mLibraryPackagesRefid = libraryPackagesRefid; } + public void setProguardFile(Path proguardFile) { + mProguardFile = TaskHelper.checkSinglePath("proguardFile", proguardFile); + } + /** * Returns an object representing a nested <var>nocompress</var> element. */ @@ -344,6 +349,11 @@ public final class AaptExecTask extends SingleDependencyTask { return path; } + @Override + protected String getExecTaskName() { + return "aapt"; + } + /* * (non-Javadoc) * @@ -375,24 +385,6 @@ public final class AaptExecTask extends SingleDependencyTask { libPkgProp = libPkgProp.replace(';', ':'); } } - // Call aapt. If there are libraries, we'll pass a non-null string of libs. - callAapt(libPkgProp); - } - - @Override - protected String getExecTaskName() { - return "aapt"; - } - - /** - * Calls aapt with the given parameters. - * @param resourceFilter the resource configuration filter to pass to aapt (if configName is - * non null) - * @param extraPackages an optional list of colon-separated packages. Can be null - * Ex: com.foo.one:com.foo.two:com.foo.lib - */ - private void callAapt(String extraPackages) { - Project taskProject = getProject(); final boolean generateRClass = mRFolder != null && new File(mRFolder).isDirectory(); @@ -538,9 +530,9 @@ public final class AaptExecTask extends SingleDependencyTask { } } - if (mNonConstantId == false && extraPackages != null && extraPackages.length() > 0) { + if (mNonConstantId == false && libPkgProp != null && libPkgProp.length() > 0) { task.createArg().setValue("--extra-packages"); - task.createArg().setValue(extraPackages); + task.createArg().setValue(libPkgProp); } // if the project contains libraries, force auto-add-overlay @@ -635,6 +627,12 @@ public final class AaptExecTask extends SingleDependencyTask { // Use dependency generation task.createArg().setValue("--generate-dependencies"); + // use the proguard file + if (mProguardFile != null && mProguardFile.length() > 0) { + task.createArg().setValue("-G"); + task.createArg().setValue(mProguardFile); + } + // final setup of the task task.setProject(taskProject); task.setOwningTarget(getOwningTarget()); diff --git a/apigenerator/src/com/android/apigenerator/AndroidJarReader.java b/apigenerator/src/com/android/apigenerator/AndroidJarReader.java new file mode 100644 index 0000000..89924a5 --- /dev/null +++ b/apigenerator/src/com/android/apigenerator/AndroidJarReader.java @@ -0,0 +1,253 @@ +/* + * 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.apigenerator; + +import com.android.util.Pair; + +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.FieldNode; +import org.objectweb.asm.tree.MethodNode; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.net.MalformedURLException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; + +/** + * Reads all the android.jar files found in an SDK and generate a map of {@link ApiClass}. + * + */ +public class AndroidJarReader { + + private static final byte[] BUFFER = new byte[65535]; + + private final String mSdkFolder; + + public AndroidJarReader(String sdkFolder) { + mSdkFolder = sdkFolder; + } + + public Map<String, ApiClass> getClasses() { + HashMap<String, ApiClass> map = new HashMap<String, ApiClass>(); + + // Get all the android.jar. They are in platforms-# + int apiLevel = 0; + while (true) { + apiLevel++; + try { + File jar = new File(mSdkFolder, "platforms/android-" + apiLevel + "/android.jar"); + if (jar.exists() == false) { + System.out.println("Last API level found: " + (apiLevel-1)); + break; + } + + FileInputStream fis = new FileInputStream(jar); + ZipInputStream zis = new ZipInputStream(fis); + ZipEntry entry = zis.getNextEntry(); + while (entry != null) { + String name = entry.getName(); + + if (name.endsWith(".class")) { + + int index = 0; + do { + int size = zis.read(BUFFER, index, BUFFER.length - index); + if (size >= 0) { + index += size; + } else { + break; + } + } while (true); + + byte[] b = new byte[index]; + System.arraycopy(BUFFER, 0, b, 0, index); + + ClassReader reader = new ClassReader(b); + ClassNode classNode = new ClassNode(); + reader.accept(classNode, 0 /*flags*/); + + if (classNode != null) { + ApiClass theClass = addClass(map, classNode.name, apiLevel); + + // super class + if (classNode.superName != null) { + theClass.addSuperClass(classNode.superName, apiLevel); + } + + // interfaces + for (Object interfaceName : classNode.interfaces) { + theClass.addInterface((String) interfaceName, apiLevel); + } + + // fields + for (Object field : classNode.fields) { + FieldNode fieldNode = (FieldNode) field; + if ((fieldNode.access & Opcodes.ACC_PRIVATE) != 0) { + continue; + } + if (fieldNode.name.startsWith("this$") == false && + fieldNode.name.equals("$VALUES") == false) { + theClass.addField(fieldNode.name, apiLevel); + } + } + + // methods + for (Object method : classNode.methods) { + MethodNode methodNode = (MethodNode) method; + if ((methodNode.access & Opcodes.ACC_PRIVATE) != 0) { + continue; + } + if (methodNode.name.equals("<clinit>") == false) { + theClass.addMethod(methodNode.name + methodNode.desc, apiLevel); + } + } + } + } + entry = zis.getNextEntry(); + } + + } catch (MalformedURLException e) { + e.printStackTrace(); + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + + } + } + + postProcessClasses(map); + + return map; + } + + private void postProcessClasses(Map<String, ApiClass> classes) { + for (ApiClass theClass : classes.values()) { + Map<String, Integer> methods = theClass.getMethods(); + Map<String, Integer> fixedMethods = new HashMap<String, Integer>(); + + List<Pair<String, Integer>> superClasses = theClass.getSuperClasses(); + List<Pair<String, Integer>> interfaces = theClass.getInterfaces(); + + methodLoop: for (Entry<String, Integer> method : methods.entrySet()) { + String methodName = method.getKey(); + int apiLevel = method.getValue(); + + if (methodName.startsWith("<init>(") == false) { + + for (Pair<String, Integer> parent : superClasses) { + // only check the parent if it was a parent class at the introduction + // of the method. + if (parent.getSecond() <= apiLevel) { + ApiClass parentClass = classes.get(parent.getFirst()); + assert parentClass != null; + if (parentClass != null && + checkClassContains(theClass.getName(), + methodName, apiLevel, + classes, parentClass)) { + continue methodLoop; + } + } + } + + for (Pair<String, Integer> parent : interfaces) { + // only check the parent if it was a parent class at the introduction + // of the method. + if (parent.getSecond() <= apiLevel) { + ApiClass parentClass = classes.get(parent.getFirst()); + assert parentClass != null; + if (parentClass != null && + checkClassContains(theClass.getName(), + methodName, apiLevel, + classes, parentClass)) { + continue methodLoop; + } + } + } + } + + // if we reach here. the method isn't an override + fixedMethods.put(methodName, method.getValue()); + } + + theClass.replaceMethods(fixedMethods); + } + } + + private boolean checkClassContains(String className, String methodName, int apiLevel, + Map<String, ApiClass> classMap, ApiClass parentClass) { + + Integer parentMethodApiLevel = parentClass.getMethods().get(methodName); + if (parentMethodApiLevel != null && parentMethodApiLevel <= apiLevel) { + // the parent class has the method and it was introduced in the parent at the + // same api level as the method, or before. + return true; + } + + // check on this class parents. + List<Pair<String, Integer>> superClasses = parentClass.getSuperClasses(); + List<Pair<String, Integer>> interfaces = parentClass.getInterfaces(); + + for (Pair<String, Integer> parent : superClasses) { + // only check the parent if it was a parent class at the introduction + // of the method. + if (parent.getSecond() <= apiLevel) { + ApiClass superParentClass = classMap.get(parent.getFirst()); + assert superParentClass != null; + if (superParentClass != null && checkClassContains(className, methodName, apiLevel, + classMap, superParentClass)) { + return true; + } + } + } + + for (Pair<String, Integer> parent : interfaces) { + // only check the parent if it was a parent class at the introduction + // of the method. + if (parent.getSecond() <= apiLevel) { + ApiClass superParentClass = classMap.get(parent.getFirst()); + assert superParentClass != null; + if (superParentClass != null && checkClassContains(className, methodName, apiLevel, + classMap, superParentClass)) { + return true; + } + } + } + + return false; + } + + private ApiClass addClass(HashMap<String, ApiClass> classes, String name, int apiLevel) { + ApiClass theClass = classes.get(name); + if (theClass == null) { + theClass = new ApiClass(name, apiLevel); + classes.put(name, theClass); + } + + return theClass; + } +} diff --git a/apigenerator/src/com/android/apigenerator/ApiClass.java b/apigenerator/src/com/android/apigenerator/ApiClass.java index 13b2d42..ccdc075 100644 --- a/apigenerator/src/com/android/apigenerator/ApiClass.java +++ b/apigenerator/src/com/android/apigenerator/ApiClass.java @@ -20,6 +20,8 @@ import com.android.util.Pair; import java.io.PrintStream; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -49,6 +51,10 @@ public class ApiClass { mSince = since; } + public String getName() { + return mName; + } + int getSince() { return mSince; } @@ -67,18 +73,35 @@ public class ApiClass { } } + public Map<String, Integer> getMethods() { + return mMethods; + } + + public void replaceMethods(Map<String, Integer> fixedMethods) { + mMethods.clear(); + mMethods.putAll(fixedMethods); + } + public void addSuperClass(String superClass, int since) { addToArray(mSuperClasses, superClass, since); } + public List<Pair<String, Integer>> getSuperClasses() { + return mSuperClasses; + } + public void addInterface(String interfaceClass, int since) { addToArray(mInterfaces, interfaceClass, since); } + public List<Pair<String, Integer>> getInterfaces() { + return mInterfaces; + } + void addToArray(List<Pair<String, Integer>> list, String name, int value) { // check if we already have that name (at a lower level) for (Pair<String, Integer> pair : list) { - if (name.equals(pair.getFirst())) { + if (name.equals(pair.getFirst()) && pair.getSecond() < value) { return; } } @@ -102,6 +125,13 @@ public class ApiClass { } private void print(List<Pair<String, Integer> > list, String name, PrintStream stream) { + Collections.sort(list, new Comparator<Pair<String, Integer> >() { + + @Override + public int compare(Pair<String, Integer> o1, Pair<String, Integer> o2) { + return o1.getFirst().compareTo(o2.getFirst()); + } + }); for (Pair<String, Integer> pair : list) { if (mSince == pair.getSecond()) { diff --git a/apigenerator/src/com/android/apigenerator/ApiParseException.java b/apigenerator/src/com/android/apigenerator/ApiParseException.java deleted file mode 100644 index 7fc8bde..0000000 --- a/apigenerator/src/com/android/apigenerator/ApiParseException.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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.apigenerator; - - -/** - * Basic exception used by {@link NewApiParser}. - * - * This is adapted from doclava. - * - */ -public final class ApiParseException extends Exception { - private static final long serialVersionUID = 1L; - - public String file; - public int line; - - public ApiParseException() { - } - - public ApiParseException(String message) { - super(message); - } - - public ApiParseException(String message, Exception cause) { - super(message, cause); - if (cause instanceof ApiParseException) { - this.line = ((ApiParseException) cause).line; - } - } - - public ApiParseException(String message, int line) { - super(message); - this.line = line; - } - - @Override - public String getMessage() { - if (line > 0) { - return super.getMessage() + " line " + line; - } else { - return super.getMessage(); - } - } -} diff --git a/apigenerator/src/com/android/apigenerator/EnumParser.java b/apigenerator/src/com/android/apigenerator/EnumParser.java deleted file mode 100644 index 18c0a94..0000000 --- a/apigenerator/src/com/android/apigenerator/EnumParser.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * 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.apigenerator; - -import org.xml.sax.Attributes; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; - -import java.io.IOException; -import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - -/** - * Parser for the simplified XML API format version 1. - */ -public class EnumParser extends DefaultHandler { - - private final static String NODE_API = "api"; - private final static String NODE_CLASS = "class"; - private final static String NODE_FIELD = "field"; - private final static String NODE_METHOD = "method"; - private final static String NODE_EXTENDS = "extends"; - private final static String NODE_IMPLEMENTS = "implements"; - - private final static String ATTR_NAME = "name"; - private final static String ATTR_SINCE = "since"; - - private final Map<String, ApiClass> mClasses = new HashMap<String, ApiClass>(); - - private ApiClass mCurrentClass; - - public EnumParser() { - } - - public Map<String, ApiClass> getClasses() { - return mClasses; - } - - @Override - public void startElement(String uri, String localName, String qName, Attributes attributes) - throws SAXException { - - if (localName == null || localName.length() == 0) { - localName = qName; - } - - try { - if (NODE_API.equals(localName)) { - // do nothing. - - } else if (NODE_CLASS.equals(localName)) { - String name = attributes.getValue(ATTR_NAME); - int since = Integer.parseInt(attributes.getValue(ATTR_SINCE)); - - mCurrentClass = addClass(name, since); - - } else if (NODE_EXTENDS.equals(localName)) { - String name = attributes.getValue(ATTR_NAME); - int since = getSince(attributes); - - mCurrentClass.addSuperClass(name, since); - - } else if (NODE_IMPLEMENTS.equals(localName)) { - String name = attributes.getValue(ATTR_NAME); - int since = getSince(attributes); - - mCurrentClass.addInterface(name, since); - - } else if (NODE_METHOD.equals(localName)) { - String name = attributes.getValue(ATTR_NAME); - int since = getSince(attributes); - - mCurrentClass.addMethod(name, since); - - } else if (NODE_FIELD.equals(localName)) { - String name = attributes.getValue(ATTR_NAME); - int since = getSince(attributes); - - mCurrentClass.addField(name, since); - - } - - } finally { - super.startElement(uri, localName, qName, attributes); - } - } - - private ApiClass addClass(String name, int apiLevel) { - ApiClass theClass = mClasses.get(name); - if (theClass == null) { - theClass = new ApiClass(name, apiLevel); - mClasses.put(name, theClass); - } - - return theClass; - } - - private int getSince(Attributes attributes) { - int since = mCurrentClass.getSince(); - String sinceAttr = attributes.getValue(ATTR_SINCE); - - if (sinceAttr != null) { - since = Integer.parseInt(sinceAttr); - } - - return since; - } - - public static Map<String, ApiClass> parseApi(InputStream stream) { - try { - SAXParserFactory parserFactory = SAXParserFactory.newInstance(); - SAXParser parser = parserFactory.newSAXParser(); - EnumParser apiParser = new EnumParser(); - parser.parse(stream, apiParser); - - return apiParser.getClasses(); - } catch (ParserConfigurationException e) { - e.printStackTrace(); - } catch (SAXException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - - return null; - } - -} diff --git a/apigenerator/src/com/android/apigenerator/Main.java b/apigenerator/src/com/android/apigenerator/Main.java index 5c26e14..4ce7ac9 100644 --- a/apigenerator/src/com/android/apigenerator/Main.java +++ b/apigenerator/src/com/android/apigenerator/Main.java @@ -17,24 +17,13 @@ package com.android.apigenerator; -import com.android.apigenerator.enumfix.AndroidJarReader; - -import org.xml.sax.SAXException; import java.io.File; -import java.io.FileInputStream; import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; import java.io.PrintStream; -import java.util.HashMap; import java.util.Map; import java.util.TreeMap; -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; - /** * Main class for command line command to convert the existing API XML/TXT files into diff-based * simple text files. @@ -46,98 +35,22 @@ public class Main { * @param args */ public static void main(String[] args) { - if (args.length < 2 || args.length > 3) { + if (args.length != 2) { printUsage(); } - if (args.length == 3) { - if (args[0].equals("enum")) { - AndroidJarReader reader = new AndroidJarReader(args[1]); - Map<String, ApiClass> classes = reader.getEnumClasses(); - createApiFile(new File(args[2]), classes); - } else { - printUsage(); - } - } else { - Map<String, ApiClass> classes = parsePlatformApiFiles(new File(args[0])); - createApiFile(new File(args[1]), classes); - } - + AndroidJarReader reader = new AndroidJarReader(args[0]); + Map<String, ApiClass> classes = reader.getClasses(); + createApiFile(new File(args[1]), classes); } private static void printUsage() { - System.err.println("Convert API files into a more manageable file\n"); + System.err.println("Generates a single API file from the content of an SDK.\n"); System.err.println("Usage\n"); - System.err.println("\tApiCheck [enum] FOLDER OUTFILE\n"); + System.err.println("\tApiCheck SDKFOLDER OUTFILE\n"); System.exit(1); } - - /** - * Parses platform API files. - * @param apiFolder the folder containing the files. - * @return a top level {@link ApiInfo} object for the highest available API level. - */ - private static Map<String, ApiClass> parsePlatformApiFiles(File apiFolder) { - int apiLevel = 1; - - Map<String, ApiClass> map = new HashMap<String, ApiClass>(); - - InputStream stream = Main.class.getResourceAsStream( - "enums.xml"); - if (stream != null) { - map = EnumParser.parseApi(stream); - } - - if (map == null) { - map = new HashMap<String, ApiClass>(); - } - - while (true) { - File file = new File(apiFolder, Integer.toString(apiLevel) + ".xml"); - if (file.exists()) { - parseXmlApiFile(file, apiLevel, map); - apiLevel++; - } else { - file = new File(apiFolder, Integer.toString(apiLevel) + ".txt"); - if (file.exists()) { - parseTxtApiFile(file, apiLevel, map); - apiLevel++; - - } else { - break; - } - } - } - - return map; - } - - private static void parseTxtApiFile(File apiFile, int api, Map<String, ApiClass> map) { - try { - NewApiParser.parseApi(apiFile.getName(), new FileInputStream(apiFile), map, api); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (ApiParseException e) { - e.printStackTrace(); - } - } - - private static void parseXmlApiFile(File apiFile, int apiLevel, - Map<String, ApiClass> map) { - try { - SAXParserFactory parserFactory = SAXParserFactory.newInstance(); - SAXParser parser = parserFactory.newSAXParser(); - parser.parse(new FileInputStream(apiFile), new XmlApiParser(map, apiLevel)); - } catch (ParserConfigurationException e) { - e.printStackTrace(); - } catch (SAXException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } - } - /** * Creates the simplified diff-based API level. * @param outFolder the out folder. diff --git a/apigenerator/src/com/android/apigenerator/NewApiParser.java b/apigenerator/src/com/android/apigenerator/NewApiParser.java deleted file mode 100644 index 91cb1e2..0000000 --- a/apigenerator/src/com/android/apigenerator/NewApiParser.java +++ /dev/null @@ -1,619 +0,0 @@ -/* - * 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.apigenerator; - -import java.io.IOException; -import java.io.InputStream; -import java.util.Map; - -/** - * Parser for the new format of platform API files. This is adapted from the Doclava code. - * - */ -class NewApiParser { - - public static void parseApi(String filename, InputStream stream, - Map<String, ApiClass> classes, int api) throws ApiParseException { - final int CHUNK = 1024 * 1024; - int hint = 0; - try { - hint = stream.available() + CHUNK; - } catch (IOException ex) { - } - - if (hint < CHUNK) { - hint = CHUNK; - } - - byte[] buf = new byte[hint]; - int size = 0; - - try { - while (true) { - if (size == buf.length) { - byte[] tmp = new byte[buf.length + CHUNK]; - System.arraycopy(buf, 0, tmp, 0, buf.length); - buf = tmp; - } - int amt = stream.read(buf, size, (buf.length - size)); - if (amt < 0) { - break; - } else { - size += amt; - } - } - } catch (IOException ex) { - throw new ApiParseException("Error reading API file", ex); - } - - final Tokenizer tokenizer = new Tokenizer(filename, - (new String(buf, 0, size)).toCharArray()); - - final ParserState state = new ParserState(classes, api); - - while (true) { - String token = tokenizer.getToken(); - if (token == null) { - break; - } - if ("package".equals(token)) { - parsePackage(state, tokenizer); - } else { - throw new ApiParseException("expected package got " + token, tokenizer.getLine()); - } - } - } - - private static void parsePackage(ParserState state, Tokenizer tokenizer) - throws ApiParseException { - String token; - String name; - - token = tokenizer.requireToken(); - assertIdent(tokenizer, token); - name = token; - - state.addPackage(name); - - token = tokenizer.requireToken(); - if (!"{".equals(token)) { - throw new ApiParseException("expected '{' got " + token, tokenizer.getLine()); - } - while (true) { - token = tokenizer.requireToken(); - if ("}".equals(token)) { - break; - } else { - parseClass(state, tokenizer, token); - } - } - - state.finishPackage(); - } - - private static void parseClass(ParserState state, Tokenizer tokenizer, String token) - throws ApiParseException { - boolean pub = false; - boolean prot = false; - boolean pkgpriv = false; - boolean stat = false; - boolean fin = false; - boolean abs = false; - boolean dep = false; - boolean iface; - String name; - String qname; - - // even though we don't care about all those parameters, we keep this parsing logic - // to make sure we go through all the tokens. - - if ("public".equals(token)) { - pub = true; - token = tokenizer.requireToken(); - } else if ("protected".equals(token)) { - prot = true; - token = tokenizer.requireToken(); - } else { - pkgpriv = true; - } - if ("static".equals(token)) { - stat = true; - token = tokenizer.requireToken(); - } - if ("final".equals(token)) { - fin = true; - token = tokenizer.requireToken(); - } - if ("abstract".equals(token)) { - abs = true; - token = tokenizer.requireToken(); - } - if ("deprecated".equals(token)) { - dep = true; - token = tokenizer.requireToken(); - } - if ("class".equals(token)) { - iface = false; - token = tokenizer.requireToken(); - } else if ("interface".equals(token)) { - iface = true; - token = tokenizer.requireToken(); - } else { - throw new ApiParseException("missing class or interface. got: " + token, - tokenizer.getLine()); - } - assertIdent(tokenizer, token); - name = token; - token = tokenizer.requireToken(); - - state.addClass(name); - - // even though we don't care about all those parameters, we keep this parsing logic - // to make sure we go through all the tokens. - - - if ("extends".equals(token)) { - token = tokenizer.requireToken(); - assertIdent(tokenizer, token); - state.addSuperClass(token); - token = tokenizer.requireToken(); - } - - // Resolve superclass after done parsing - if ("implements".equals(token)) { - while (true) { - token = tokenizer.requireToken(); - if ("{".equals(token)) { - break; - } else { - if (!",".equals(token)) { - state.addInterface(token); - } - } - } - } - - if (!"{".equals(token)) { - throw new ApiParseException("expected {", tokenizer.getLine()); - } - - token = tokenizer.requireToken(); - while (true) { - if ("}".equals(token)) { - break; - } else if ("ctor".equals(token)) { - token = tokenizer.requireToken(); - parseConstructor(tokenizer, state, token); - } else if ("method".equals(token)) { - token = tokenizer.requireToken(); - parseMethod(tokenizer, state, token); - } else if ("field".equals(token)) { - token = tokenizer.requireToken(); - parseField(tokenizer, state, token, false); - } else if ("enum_constant".equals(token)) { - token = tokenizer.requireToken(); - parseField(tokenizer, state, token, true); - } else { - throw new ApiParseException("expected ctor, enum_constant, field or method", - tokenizer.getLine()); - } - token = tokenizer.requireToken(); - } - - state.finishClass(); - } - - private static void parseConstructor(Tokenizer tokenizer, ParserState state, String token) - throws ApiParseException { - boolean pub = false; - boolean prot = false; - boolean pkgpriv = false; - boolean dep = false; - String name; - - if ("public".equals(token)) { - pub = true; - token = tokenizer.requireToken(); - } else if ("protected".equals(token)) { - prot = true; - token = tokenizer.requireToken(); - } else { - pkgpriv = true; - } - if ("deprecated".equals(token)) { - dep = true; - token = tokenizer.requireToken(); - } - assertIdent(tokenizer, token); - name = token; - token = tokenizer.requireToken(); - if (!"(".equals(token)) { - throw new ApiParseException("expected (", tokenizer.getLine()); - } - - state.startNewConstructor(); - - token = tokenizer.requireToken(); - parseParameterList(tokenizer, state, token); - token = tokenizer.requireToken(); - if ("throws".equals(token)) { - token = parseThrows(tokenizer, state); - } - if (!";".equals(token)) { - throw new ApiParseException("expected ; found " + token, tokenizer.getLine()); - } - - state.finishMethod(); - } - - private static void parseMethod(Tokenizer tokenizer, ParserState state, String token) - throws ApiParseException { - boolean pub = false; - boolean prot = false; - boolean pkgpriv = false; - boolean stat = false; - boolean fin = false; - boolean abs = false; - boolean dep = false; - boolean syn = false; - String type; - String name; - String ext = null; - - if ("public".equals(token)) { - pub = true; - token = tokenizer.requireToken(); - } else if ("protected".equals(token)) { - prot = true; - token = tokenizer.requireToken(); - } else { - pkgpriv = true; - } - if ("static".equals(token)) { - stat = true; - token = tokenizer.requireToken(); - } - if ("final".equals(token)) { - fin = true; - token = tokenizer.requireToken(); - } - if ("abstract".equals(token)) { - abs = true; - token = tokenizer.requireToken(); - } - if ("deprecated".equals(token)) { - dep = true; - token = tokenizer.requireToken(); - } - if ("synchronized".equals(token)) { - syn = true; - token = tokenizer.requireToken(); - } - assertIdent(tokenizer, token); - type = token; - token = tokenizer.requireToken(); - assertIdent(tokenizer, token); - name = token; - - state.startNewMethod(name, type); - - token = tokenizer.requireToken(); - if (!"(".equals(token)) { - throw new ApiParseException("expected (", tokenizer.getLine()); - } - token = tokenizer.requireToken(); - parseParameterList(tokenizer, state, token); - token = tokenizer.requireToken(); - if ("throws".equals(token)) { - token = parseThrows(tokenizer, state); - } - if (!";".equals(token)) { - throw new ApiParseException("expected ; found " + token, tokenizer.getLine()); - } - - state.finishMethod(); - } - - private static void parseField(Tokenizer tokenizer, ParserState state, String token, boolean isEnum) - throws ApiParseException { - boolean pub = false; - boolean prot = false; - boolean pkgpriv = false; - boolean stat = false; - boolean fin = false; - boolean dep = false; - boolean trans = false; - boolean vol = false; - String type; - String name; - String val = null; - Object v; - - if ("public".equals(token)) { - pub = true; - token = tokenizer.requireToken(); - } else if ("protected".equals(token)) { - prot = true; - token = tokenizer.requireToken(); - } else { - pkgpriv = true; - } - if ("static".equals(token)) { - stat = true; - token = tokenizer.requireToken(); - } - if ("final".equals(token)) { - fin = true; - token = tokenizer.requireToken(); - } - if ("deprecated".equals(token)) { - dep = true; - token = tokenizer.requireToken(); - } - if ("transient".equals(token)) { - trans = true; - token = tokenizer.requireToken(); - } - if ("volatile".equals(token)) { - vol = true; - token = tokenizer.requireToken(); - } - assertIdent(tokenizer, token); - type = token; - token = tokenizer.requireToken(); - assertIdent(tokenizer, token); - name = token; - token = tokenizer.requireToken(); - if ("=".equals(token)) { - token = tokenizer.requireToken(false); - val = token; - token = tokenizer.requireToken(); - } - if (!";".equals(token)) { - throw new ApiParseException("expected ; found " + token, tokenizer.getLine()); - } - - if (isEnum) { - state.addField(name); - } else { - state.addField(name); - } - } - - private static void parseParameterList(Tokenizer tokenizer, ParserState state, - String token) throws ApiParseException { - while (true) { - if (")".equals(token)) { - return; - } - - String type = token; - String name = null; - token = tokenizer.requireToken(); - if (isIdent(token)) { - name = token; - token = tokenizer.requireToken(); - } - if (",".equals(token)) { - token = tokenizer.requireToken(); - } else if (")".equals(token)) { - } else { - throw new ApiParseException("expected , found " + token, tokenizer.getLine()); - } - state.addMethodParameter(type); -// method.addParameter(new ParameterInfo(name, type, Converter.obtainTypeFromString(type), -// type.endsWith("..."), tokenizer.pos())); - } - } - - private static String parseThrows(Tokenizer tokenizer, ParserState state) - throws ApiParseException { - String token = tokenizer.requireToken(); - boolean comma = true; - while (true) { - if (";".equals(token)) { - return token; - } else if (",".equals(token)) { - if (comma) { - throw new ApiParseException("Expected exception, got ','", tokenizer.getLine()); - } - comma = true; - } else { - if (!comma) { - throw new ApiParseException("Expected ',' or ';' got " + token, - tokenizer.getLine()); - } - comma = false; - } - token = tokenizer.requireToken(); - } - } - -// private static String qualifiedName(String pkg, String className, ClassInfo parent) { -// String parentQName = (parent != null) ? (parent.qualifiedName() + ".") : ""; -// return pkg + "." + parentQName + className; -// } - - private static boolean isIdent(String token) { - return isident(token.charAt(0)); - } - - private static void assertIdent(Tokenizer tokenizer, String token) throws ApiParseException { - if (!isident(token.charAt(0))) { - throw new ApiParseException("Expected identifier: " + token, tokenizer.getLine()); - } - } - - static class Tokenizer { - char[] mBuf; - - String mFilename; - - int mPos; - - int mLine = 1; - - Tokenizer(String filename, char[] buf) { - mFilename = filename; - mBuf = buf; - } - - public int getLine() { - return mLine; - } - - boolean eatWhitespace() { - boolean ate = false; - while (mPos < mBuf.length && isspace(mBuf[mPos])) { - if (mBuf[mPos] == '\n') { - mLine++; - } - mPos++; - ate = true; - } - return ate; - } - - boolean eatComment() { - if (mPos + 1 < mBuf.length) { - if (mBuf[mPos] == '/' && mBuf[mPos + 1] == '/') { - mPos += 2; - while (mPos < mBuf.length && !isnewline(mBuf[mPos])) { - mPos++; - } - return true; - } - } - return false; - } - - void eatWhitespaceAndComments() { - while (eatWhitespace() || eatComment()) { - } - } - - public String requireToken() throws ApiParseException { - return requireToken(true); - } - - public String requireToken(boolean parenIsSep) throws ApiParseException { - final String token = getToken(parenIsSep); - if (token != null) { - return token; - } else { - throw new ApiParseException("Unexpected end of file", mLine); - } - } - - public String getToken() throws ApiParseException { - return getToken(true); - } - - public String getToken(boolean parenIsSep) throws ApiParseException { - eatWhitespaceAndComments(); - if (mPos >= mBuf.length) { - return null; - } - final int line = mLine; - final char c = mBuf[mPos]; - final int start = mPos; - mPos++; - if (c == '"') { - final int STATE_BEGIN = 0; - final int STATE_ESCAPE = 1; - int state = STATE_BEGIN; - while (true) { - if (mPos >= mBuf.length) { - throw new ApiParseException("Unexpected end of file for \" starting at " - + line, mLine); - } - final char k = mBuf[mPos]; - if (k == '\n' || k == '\r') { - throw new ApiParseException( - "Unexpected newline for \" starting at " + line, mLine); - } - mPos++; - switch (state) { - case STATE_BEGIN: - switch (k) { - case '\\': - state = STATE_ESCAPE; - mPos++; - break; - case '"': - return new String(mBuf, start, mPos - start); - } - case STATE_ESCAPE: - state = STATE_BEGIN; - break; - } - } - } else if (issep(c, parenIsSep)) { - return "" + c; - } else { - int genericDepth = 0; - do { - while (mPos < mBuf.length && !isspace(mBuf[mPos]) - && !issep(mBuf[mPos], parenIsSep)) { - mPos++; - } - if (mPos < mBuf.length) { - if (mBuf[mPos] == '<') { - genericDepth++; - mPos++; - } else if (mBuf[mPos] == '>') { - genericDepth--; - mPos++; - } else if (genericDepth != 0) { - mPos++; - } - } - } while (mPos < mBuf.length - && ((!isspace(mBuf[mPos]) && !issep(mBuf[mPos], parenIsSep)) || genericDepth != 0)); - if (mPos >= mBuf.length) { - throw new ApiParseException( - "Unexpected end of file for \" starting at " + line, mLine); - } - return new String(mBuf, start, mPos - start); - } - } - } - - static boolean isspace(char c) { - return c == ' ' || c == '\t' || c == '\n' || c == '\r'; - } - - static boolean isnewline(char c) { - return c == '\n' || c == '\r'; - } - - static boolean issep(char c, boolean parenIsSep) { - if (parenIsSep) { - if (c == '(' || c == ')') { - return true; - } - } - return c == '{' || c == '}' || c == ',' || c == ';' || c == '<' || c == '>'; - } - - static boolean isident(char c) { - if (c == '"' || issep(c, true)) { - return false; - } - return true; - } -} diff --git a/apigenerator/src/com/android/apigenerator/ParserState.java b/apigenerator/src/com/android/apigenerator/ParserState.java deleted file mode 100644 index 7ffb57a..0000000 --- a/apigenerator/src/com/android/apigenerator/ParserState.java +++ /dev/null @@ -1,174 +0,0 @@ -/* - * 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.apigenerator; - -import java.util.Map; - -/** - * Parser state used during parsing of the platform API files. - * - */ -class ParserState { - - private final int mApiLevel; - - private final Map<String, ApiClass> mClasses; - - private String mCurrentPackage; - private ApiClass mCurrentClass; - - private String mMethodName; - private StringBuilder mMethodParams = new StringBuilder(); - private String mMethodReturnType; - - ParserState(Map<String, ApiClass> classes, int apiLevel) { - mClasses = classes; - mApiLevel = apiLevel; - } - - Map<String, ApiClass> getClasses() { - return mClasses; - } - - void addPackage(String packageName) { - mCurrentPackage = packageName; - } - - void addClass(String className) { - String fqcn = makeJavaClass(mCurrentPackage + "." + className); - mCurrentClass = addClass(fqcn, mApiLevel); - } - - void addSuperClass(String superClass) { - mCurrentClass.addSuperClass(makeJavaClass(superClass), mApiLevel); - } - - void addInterface(String interfaceClass) { - mCurrentClass.addInterface(makeJavaClass(interfaceClass), mApiLevel); - } - - void startNewConstructor() { - mMethodParams.setLength(0); - mMethodName = "<init>"; - mMethodReturnType = "V"; - } - - void startNewMethod(String name, String returnType) { - mMethodParams.setLength(0); - mMethodName = name; - mMethodReturnType = parseType(returnType); - } - - void addMethodParameter(String parameter) { - mMethodParams.append(parseType(parameter)); - } - - void finishMethod() { - addMethod(mMethodName + "(" + mMethodParams.toString() + ")" + - (mMethodReturnType != null ? mMethodReturnType : "")); - } - - void addMethod(String methodSignature) { - mCurrentClass.addMethod(methodSignature, mApiLevel); - } - - void addField(String fieldName) { - mCurrentClass.addField(fieldName, mApiLevel); - } - - void finishClass() { - mCurrentClass = null; - } - - void finishPackage() { - finishClass(); - mCurrentPackage = null; - } - - void done() { - finishPackage(); - } - - private ApiClass addClass(String name, int apiLevel) { - ApiClass theClass = mClasses.get(name); - if (theClass == null) { - theClass = new ApiClass(name, apiLevel); - mClasses.put(name, theClass); - } - - return theClass; - } - - - private String makeJavaClass(String fqcn) { - final int length = fqcn.length(); - - StringBuilder sb = new StringBuilder(length); - - boolean isClass = Character.isUpperCase(fqcn.charAt(0)); - for (int i = 0 ; i < length ; i++) { - if (fqcn.charAt(i) == '.') { - if (isClass) { - sb.append('$'); - } else { - sb.append('/'); - } - - if (i < length -1 ) { - isClass = Character.isUpperCase(fqcn.charAt(i+1)); - } - } else { - if (fqcn.charAt(i) == '<') { - break; - } - - sb.append(fqcn.charAt(i)); - } - } - - return sb.toString(); - } - - private String parseType(String type) { - StringBuilder result = new StringBuilder(); - - if (type.endsWith("...")) { - result.append('['); - type = type.substring(0, type.length() - 3); - } - - while (type.endsWith("[]")) { - result.append('['); - type = type.substring(0, type.length() - 2); - } - - if ("byte".equals(type)) result.append('B'); - else if ("char".equals(type)) result.append('C'); - else if ("double".equals(type)) result.append('D'); - else if ("float".equals(type)) result.append('F'); - else if ("int".equals(type)) result.append('I'); - else if ("long".equals(type)) result.append('J'); - else if ("short".equals(type)) result.append('S'); - else if ("void".equals(type)) result.append('V'); - else if ("boolean".equals(type)) result.append('Z'); - else { - result.append('L').append(makeJavaClass(type)).append(';'); - } - - return result.toString(); - } -} diff --git a/apigenerator/src/com/android/apigenerator/XmlApiParser.java b/apigenerator/src/com/android/apigenerator/XmlApiParser.java deleted file mode 100644 index 840272c..0000000 --- a/apigenerator/src/com/android/apigenerator/XmlApiParser.java +++ /dev/null @@ -1,126 +0,0 @@ -/* - * 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.apigenerator; - -import org.xml.sax.Attributes; -import org.xml.sax.SAXException; -import org.xml.sax.helpers.DefaultHandler; - -import java.util.Map; - -/** - * Parser for the old, XML-based format of platform API files. - */ -class XmlApiParser extends DefaultHandler { - - private final static String NODE_API = "api"; - private final static String NODE_PACKAGE = "package"; - private final static String NODE_CLASS = "class"; - private final static String NODE_INTERFACE = "interface"; - private final static String NODE_IMPLEMENTS = "implements"; - private final static String NODE_FIELD = "field"; - private final static String NODE_CONSTRUCTOR = "constructor"; - private final static String NODE_METHOD = "method"; - private final static String NODE_PARAMETER = "parameter"; - - private final static String ATTR_NAME = "name"; - private final static String ATTR_TYPE = "type"; - private final static String ATTR_RETURN = "return"; - private final static String ATTR_EXTENDS = "extends"; - - private final ParserState mParserState; - - XmlApiParser(Map<String, ApiClass> map, int apiLevel) { - mParserState = new ParserState(map, apiLevel); - } - - @Override - public void startElement(String uri, String localName, String qName, Attributes attributes) - throws SAXException { - - if (localName == null || localName.length() == 0) { - localName = qName; - } - - try { - - if (NODE_API.equals(localName)) { - } else if (NODE_PACKAGE.equals(localName)) { - mParserState.addPackage(attributes.getValue(ATTR_NAME)); - - } else if (NODE_CLASS.equals(localName) || NODE_INTERFACE.equals(localName)) { - mParserState.addClass(attributes.getValue(ATTR_NAME)); - - String extendsAttr = attributes.getValue(ATTR_EXTENDS); - if (extendsAttr != null) { - mParserState.addSuperClass(extendsAttr); - } - - } else if (NODE_IMPLEMENTS.equals(localName)) { - mParserState.addInterface(attributes.getValue(ATTR_NAME)); - - } else if (NODE_FIELD.equals(localName)) { - mParserState.addField(attributes.getValue(ATTR_NAME)); - - } else if (NODE_CONSTRUCTOR.equals(localName)) { - parseConstructor(attributes); - - } else if (NODE_METHOD.equals(localName)) { - parseMethod(attributes); - - } else if (NODE_PARAMETER.equals(localName)) { - parseParameter(attributes); - } - - } finally { - super.startElement(uri, localName, qName, attributes); - } - } - - private void parseConstructor(Attributes attributes) { - mParserState.startNewConstructor(); - } - - private void parseMethod(Attributes attributes) { - mParserState.startNewMethod(attributes.getValue(ATTR_NAME), - attributes.getValue(ATTR_RETURN)); - } - - private void parseParameter(Attributes attributes) { - mParserState.addMethodParameter(attributes.getValue(ATTR_TYPE)); - } - - @Override - public void endElement(String uri, String localName, String qName) throws SAXException { - if (localName == null || localName.length() == 0) { - localName = qName; - } - - try { - - if (NODE_METHOD.equals(localName) || NODE_CONSTRUCTOR.equals(localName)) { - mParserState.finishMethod(); - - } else if (NODE_API.equals(localName)) { - mParserState.done(); - } - - } finally { - super.endElement(uri, localName, qName); - } - } -}
\ No newline at end of file diff --git a/apigenerator/src/com/android/apigenerator/enumfix/AndroidJarReader.java b/apigenerator/src/com/android/apigenerator/enumfix/AndroidJarReader.java deleted file mode 100644 index 7669786..0000000 --- a/apigenerator/src/com/android/apigenerator/enumfix/AndroidJarReader.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * 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.apigenerator.enumfix; - -import com.android.apigenerator.ApiClass; - -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.FieldNode; - -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.net.MalformedURLException; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; - -/** - * This codes looks at all the android.jar in an SDK and use ASM to figure out when enums - * where introduced. This is a one time thing that creates the file - * /com/android/apichecker/generator/enums.xml which is then used to create the final API file. - * - */ -public class AndroidJarReader { - - // this the last API until we switched to a new API format that included enum values. - private final static int MAX_API = 13; - private static final byte[] BUFFER = new byte[65535]; - - private final String mSdkFolder; - - public AndroidJarReader(String sdkFolder) { - mSdkFolder = sdkFolder; - } - - public Map<String, ApiClass> getEnumClasses() { - HashMap<String, ApiClass> map = new HashMap<String, ApiClass>(); - - // Get all the android.jar. They are in platforms-# - for (int apiLevel = 1 ; apiLevel <= MAX_API ; apiLevel++) { - try { - File jar = new File(mSdkFolder, "platforms/android-" + apiLevel + "/android.jar"); - if (jar.exists() == false) { - System.err.println("Missing android.jar for API level " + apiLevel); - continue; - } - - FileInputStream fis = new FileInputStream(jar); - ZipInputStream zis = new ZipInputStream(fis); - ZipEntry entry = zis.getNextEntry(); - while (entry != null) { - String name = entry.getName(); - - if (name.endsWith(".class")) { - - int index = 0; - do { - int size = zis.read(BUFFER, index, BUFFER.length - index); - if (size >= 0) { - index += size; - } else { - break; - } - } while (true); - - byte[] b = new byte[index]; - System.arraycopy(BUFFER, 0, b, 0, index); - - ClassReader reader = new ClassReader(b); - ClassNode classNode = new ClassNode(); - reader.accept(classNode, 0 /*flags*/); - - if (classNode != null && classNode.superName != null && - classNode.superName.equals("java/lang/Enum")) { - - ApiClass theClass = addClass(map, classNode.name, apiLevel); - theClass.addSuperClass("java/lang/Enum", apiLevel); - - List fields = classNode.fields; - for (Object f : fields) { - FieldNode fnode = (FieldNode) f; - if (fnode.desc.substring(1, fnode.desc.length() - 1).equals(classNode.name)) { - theClass.addField(fnode.name, apiLevel); - } - } - } - } - entry = zis.getNextEntry(); - } - } catch (MalformedURLException e) { - e.printStackTrace(); - } catch (FileNotFoundException e) { - e.printStackTrace(); - } catch (IOException e) { - e.printStackTrace(); - } finally { - - } - } - - return map; - } - - private ApiClass addClass(HashMap<String, ApiClass> classes, String name, int apiLevel) { - ApiClass theClass = classes.get(name); - if (theClass == null) { - theClass = new ApiClass(name, apiLevel); - classes.put(name, theClass); - } - - return theClass; - } - -} diff --git a/apigenerator/src/com/android/apigenerator/enums.xml b/apigenerator/src/com/android/apigenerator/enums.xml deleted file mode 100644 index 54a2a21..0000000 --- a/apigenerator/src/com/android/apigenerator/enums.xml +++ /dev/null @@ -1,596 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<api version="1"> - <class name="android/database/CursorJoiner$Result" since="1"> - <extends name="java/lang/Enum" /> - <field name="BOTH" /> - <field name="LEFT" /> - <field name="RIGHT" /> - </class> - <class name="android/graphics/AvoidXfermode$Mode" since="1"> - <extends name="java/lang/Enum" /> - <field name="AVOID" /> - <field name="TARGET" /> - </class> - <class name="android/graphics/Bitmap$CompressFormat" since="1"> - <extends name="java/lang/Enum" /> - <field name="JPEG" /> - <field name="PNG" /> - </class> - <class name="android/graphics/Bitmap$Config" since="1"> - <extends name="java/lang/Enum" /> - <field name="ALPHA_8" /> - <field name="ARGB_4444" /> - <field name="ARGB_8888" /> - <field name="RGB_565" /> - </class> - <class name="android/graphics/BlurMaskFilter$Blur" since="1"> - <extends name="java/lang/Enum" /> - <field name="INNER" /> - <field name="NORMAL" /> - <field name="OUTER" /> - <field name="SOLID" /> - </class> - <class name="android/graphics/Canvas$EdgeType" since="1"> - <extends name="java/lang/Enum" /> - <field name="AA" /> - <field name="BW" /> - </class> - <class name="android/graphics/Canvas$VertexMode" since="1"> - <extends name="java/lang/Enum" /> - <field name="TRIANGLES" /> - <field name="TRIANGLE_FAN" /> - <field name="TRIANGLE_STRIP" /> - </class> - <class name="android/graphics/Interpolator$Result" since="1"> - <extends name="java/lang/Enum" /> - <field name="FREEZE_END" /> - <field name="FREEZE_START" /> - <field name="NORMAL" /> - </class> - <class name="android/graphics/Matrix$ScaleToFit" since="1"> - <extends name="java/lang/Enum" /> - <field name="CENTER" /> - <field name="END" /> - <field name="FILL" /> - <field name="START" /> - </class> - <class name="android/graphics/Paint$Align" since="1"> - <extends name="java/lang/Enum" /> - <field name="CENTER" /> - <field name="LEFT" /> - <field name="RIGHT" /> - </class> - <class name="android/graphics/Paint$Cap" since="1"> - <extends name="java/lang/Enum" /> - <field name="BUTT" /> - <field name="ROUND" /> - <field name="SQUARE" /> - </class> - <class name="android/graphics/Paint$Join" since="1"> - <extends name="java/lang/Enum" /> - <field name="BEVEL" /> - <field name="MITER" /> - <field name="ROUND" /> - </class> - <class name="android/graphics/Paint$Style" since="1"> - <extends name="java/lang/Enum" /> - <field name="FILL" /> - <field name="FILL_AND_STROKE" /> - <field name="STROKE" /> - </class> - <class name="android/graphics/Path$Direction" since="1"> - <extends name="java/lang/Enum" /> - <field name="CCW" /> - <field name="CW" /> - </class> - <class name="android/graphics/Path$FillType" since="1"> - <extends name="java/lang/Enum" /> - <field name="EVEN_ODD" /> - <field name="INVERSE_EVEN_ODD" /> - <field name="INVERSE_WINDING" /> - <field name="WINDING" /> - </class> - <class name="android/graphics/PathDashPathEffect$Style" since="1"> - <extends name="java/lang/Enum" /> - <field name="MORPH" /> - <field name="ROTATE" /> - <field name="TRANSLATE" /> - </class> - <class name="android/graphics/PorterDuff$Mode" since="1"> - <extends name="java/lang/Enum" /> - <field name="ADD" since="11" /> - <field name="CLEAR" /> - <field name="DARKEN" /> - <field name="DST" /> - <field name="DST_ATOP" /> - <field name="DST_IN" /> - <field name="DST_OUT" /> - <field name="DST_OVER" /> - <field name="LIGHTEN" /> - <field name="MULTIPLY" /> - <field name="OVERLAY" since="11" /> - <field name="SCREEN" /> - <field name="SRC" /> - <field name="SRC_ATOP" /> - <field name="SRC_IN" /> - <field name="SRC_OUT" /> - <field name="SRC_OVER" /> - <field name="XOR" /> - </class> - <class name="android/graphics/Region$Op" since="1"> - <extends name="java/lang/Enum" /> - <field name="DIFFERENCE" /> - <field name="INTERSECT" /> - <field name="REPLACE" /> - <field name="REVERSE_DIFFERENCE" /> - <field name="UNION" /> - <field name="XOR" /> - </class> - <class name="android/graphics/Shader$TileMode" since="1"> - <extends name="java/lang/Enum" /> - <field name="CLAMP" /> - <field name="MIRROR" /> - <field name="REPEAT" /> - </class> - <class name="android/graphics/drawable/GradientDrawable$Orientation" since="1"> - <extends name="java/lang/Enum" /> - <field name="BL_TR" /> - <field name="BOTTOM_TOP" /> - <field name="BR_TL" /> - <field name="LEFT_RIGHT" /> - <field name="RIGHT_LEFT" /> - <field name="TL_BR" /> - <field name="TOP_BOTTOM" /> - <field name="TR_BL" /> - </class> - <class name="android/net/LocalSocketAddress$Namespace" since="1"> - <extends name="java/lang/Enum" /> - <field name="ABSTRACT" /> - <field name="FILESYSTEM" /> - <field name="RESERVED" /> - </class> - <class name="android/net/NetworkInfo$DetailedState" since="1"> - <extends name="java/lang/Enum" /> - <field name="AUTHENTICATING" /> - <field name="CONNECTED" /> - <field name="CONNECTING" /> - <field name="DISCONNECTED" /> - <field name="DISCONNECTING" /> - <field name="FAILED" /> - <field name="IDLE" /> - <field name="OBTAINING_IPADDR" /> - <field name="SCANNING" /> - <field name="SUSPENDED" /> - </class> - <class name="android/net/NetworkInfo$State" since="1"> - <extends name="java/lang/Enum" /> - <field name="CONNECTED" /> - <field name="CONNECTING" /> - <field name="DISCONNECTED" /> - <field name="DISCONNECTING" /> - <field name="SUSPENDED" /> - <field name="UNKNOWN" /> - </class> - <class name="android/net/wifi/SupplicantState" since="1"> - <extends name="java/lang/Enum" /> - <field name="ASSOCIATED" /> - <field name="ASSOCIATING" /> - <field name="COMPLETED" /> - <field name="DISCONNECTED" /> - <field name="DORMANT" /> - <field name="FOUR_WAY_HANDSHAKE" /> - <field name="GROUP_HANDSHAKE" /> - <field name="INACTIVE" /> - <field name="INVALID" /> - <field name="SCANNING" /> - <field name="UNINITIALIZED" /> - </class> - <class name="android/os/AsyncTask$Status" since="3"> - <extends name="java/lang/Enum" /> - <field name="FINISHED" /> - <field name="PENDING" /> - <field name="RUNNING" /> - </class> - <class name="android/renderscript/Allocation$MipmapControl" since="11"> - <extends name="java/lang/Enum" /> - <field name="MIPMAP_FULL" /> - <field name="MIPMAP_NONE" /> - <field name="MIPMAP_ON_SYNC_TO_TEXTURE" /> - </class> - <class name="android/renderscript/Element$DataKind" since="11"> - <extends name="java/lang/Enum" /> - <field name="PIXEL_A" /> - <field name="PIXEL_L" /> - <field name="PIXEL_LA" /> - <field name="PIXEL_RGB" /> - <field name="PIXEL_RGBA" /> - <field name="USER" /> - </class> - <class name="android/renderscript/Element$DataType" since="11"> - <extends name="java/lang/Enum" /> - <field name="BOOLEAN" /> - <field name="FLOAT_32" /> - <field name="FLOAT_64" /> - <field name="MATRIX_2X2" /> - <field name="MATRIX_3X3" /> - <field name="MATRIX_4X4" /> - <field name="RS_ALLOCATION" /> - <field name="RS_ELEMENT" /> - <field name="RS_MESH" /> - <field name="RS_PROGRAM_FRAGMENT" /> - <field name="RS_PROGRAM_RASTER" /> - <field name="RS_PROGRAM_STORE" /> - <field name="RS_PROGRAM_VERTEX" /> - <field name="RS_SAMPLER" /> - <field name="RS_SCRIPT" /> - <field name="RS_TYPE" /> - <field name="SIGNED_16" /> - <field name="SIGNED_32" /> - <field name="SIGNED_64" /> - <field name="SIGNED_8" /> - <field name="UNSIGNED_16" /> - <field name="UNSIGNED_32" /> - <field name="UNSIGNED_4_4_4_4" /> - <field name="UNSIGNED_5_5_5_1" /> - <field name="UNSIGNED_5_6_5" /> - <field name="UNSIGNED_64" /> - <field name="UNSIGNED_8" /> - </class> - <class name="android/renderscript/FileA3D$EntryType" since="11"> - <extends name="java/lang/Enum" /> - <field name="MESH" /> - <field name="UNKNOWN" /> - </class> - <class name="android/renderscript/Font$Style" since="11"> - <extends name="java/lang/Enum" /> - <field name="BOLD" /> - <field name="BOLD_ITALIC" /> - <field name="ITALIC" /> - <field name="NORMAL" /> - </class> - <class name="android/renderscript/Mesh$Primitive" since="11"> - <extends name="java/lang/Enum" /> - <field name="LINE" /> - <field name="LINE_STRIP" /> - <field name="POINT" /> - <field name="TRIANGLE" /> - <field name="TRIANGLE_FAN" /> - <field name="TRIANGLE_STRIP" /> - </class> - <class name="android/renderscript/Program$TextureType" since="11"> - <extends name="java/lang/Enum" /> - <field name="TEXTURE_2D" /> - <field name="TEXTURE_CUBE" /> - </class> - <class name="android/renderscript/ProgramFragmentFixedFunction$Builder$EnvMode" since="11"> - <extends name="java/lang/Enum" /> - <field name="DECAL" /> - <field name="MODULATE" /> - <field name="REPLACE" /> - </class> - <class name="android/renderscript/ProgramFragmentFixedFunction$Builder$Format" since="11"> - <extends name="java/lang/Enum" /> - <field name="ALPHA" /> - <field name="LUMINANCE_ALPHA" /> - <field name="RGB" /> - <field name="RGBA" /> - </class> - <class name="android/renderscript/ProgramRaster$CullMode" since="11"> - <extends name="java/lang/Enum" /> - <field name="BACK" /> - <field name="FRONT" /> - <field name="NONE" /> - </class> - <class name="android/renderscript/ProgramStore$BlendDstFunc" since="11"> - <extends name="java/lang/Enum" /> - <field name="DST_ALPHA" /> - <field name="ONE" /> - <field name="ONE_MINUS_DST_ALPHA" /> - <field name="ONE_MINUS_SRC_ALPHA" /> - <field name="ONE_MINUS_SRC_COLOR" /> - <field name="SRC_ALPHA" /> - <field name="SRC_COLOR" /> - <field name="ZERO" /> - </class> - <class name="android/renderscript/ProgramStore$BlendSrcFunc" since="11"> - <extends name="java/lang/Enum" /> - <field name="DST_ALPHA" /> - <field name="DST_COLOR" /> - <field name="ONE" /> - <field name="ONE_MINUS_DST_ALPHA" /> - <field name="ONE_MINUS_DST_COLOR" /> - <field name="ONE_MINUS_SRC_ALPHA" /> - <field name="SRC_ALPHA" /> - <field name="SRC_ALPHA_SATURATE" /> - <field name="ZERO" /> - </class> - <class name="android/renderscript/ProgramStore$DepthFunc" since="11"> - <extends name="java/lang/Enum" /> - <field name="ALWAYS" /> - <field name="EQUAL" /> - <field name="GREATER" /> - <field name="GREATER_OR_EQUAL" /> - <field name="LESS" /> - <field name="LESS_OR_EQUAL" /> - <field name="NOT_EQUAL" /> - </class> - <class name="android/renderscript/RenderScript$Priority" since="11"> - <extends name="java/lang/Enum" /> - <field name="LOW" /> - <field name="NORMAL" /> - </class> - <class name="android/renderscript/Sampler$Value" since="11"> - <extends name="java/lang/Enum" /> - <field name="CLAMP" /> - <field name="LINEAR" /> - <field name="LINEAR_MIP_LINEAR" /> - <field name="LINEAR_MIP_NEAREST" /> - <field name="NEAREST" /> - <field name="WRAP" /> - </class> - <class name="android/renderscript/Type$CubemapFace" since="11"> - <extends name="java/lang/Enum" /> - <field name="NEGATIVE_X" /> - <field name="NEGATIVE_Y" /> - <field name="NEGATIVE_Z" /> - <field name="POSITVE_X" /> - <field name="POSITVE_Y" /> - <field name="POSITVE_Z" /> - </class> - <class name="android/telephony/SmsMessage$MessageClass" since="4"> - <extends name="java/lang/Enum" /> - <field name="CLASS_0" /> - <field name="CLASS_1" /> - <field name="CLASS_2" /> - <field name="CLASS_3" /> - <field name="UNKNOWN" /> - </class> - <class name="android/telephony/gsm/SmsMessage$MessageClass" since="1"> - <extends name="java/lang/Enum" /> - <field name="CLASS_0" /> - <field name="CLASS_1" /> - <field name="CLASS_2" /> - <field name="CLASS_3" /> - <field name="UNKNOWN" /> - </class> - <class name="android/text/Layout$Alignment" since="1"> - <extends name="java/lang/Enum" /> - <field name="ALIGN_CENTER" /> - <field name="ALIGN_NORMAL" /> - <field name="ALIGN_OPPOSITE" /> - </class> - <class name="android/text/TextUtils$TruncateAt" since="1"> - <extends name="java/lang/Enum" /> - <field name="END" /> - <field name="MARQUEE" since="2" /> - <field name="MIDDLE" /> - <field name="START" /> - </class> - <class name="android/text/method/TextKeyListener$Capitalize" since="1"> - <extends name="java/lang/Enum" /> - <field name="CHARACTERS" /> - <field name="NONE" /> - <field name="SENTENCES" /> - <field name="WORDS" /> - </class> - <class name="android/util/JsonToken" since="11"> - <extends name="java/lang/Enum" /> - <field name="BEGIN_ARRAY" /> - <field name="BEGIN_OBJECT" /> - <field name="BOOLEAN" /> - <field name="END_ARRAY" /> - <field name="END_DOCUMENT" /> - <field name="END_OBJECT" /> - <field name="NAME" /> - <field name="NULL" /> - <field name="NUMBER" /> - <field name="STRING" /> - </class> - <class name="android/util/Xml$Encoding" since="1"> - <extends name="java/lang/Enum" /> - <field name="ISO_8859_1" /> - <field name="US_ASCII" /> - <field name="UTF_16" /> - <field name="UTF_8" /> - </class> - <class name="android/view/ViewDebug$HierarchyTraceType" since="1"> - <extends name="java/lang/Enum" /> - <field name="BUILD_CACHE" /> - <field name="DRAW" /> - <field name="INVALIDATE" /> - <field name="INVALIDATE_CHILD" /> - <field name="INVALIDATE_CHILD_IN_PARENT" /> - <field name="ON_LAYOUT" /> - <field name="ON_MEASURE" /> - <field name="REQUEST_LAYOUT" /> - </class> - <class name="android/view/ViewDebug$RecyclerTraceType" since="1"> - <extends name="java/lang/Enum" /> - <field name="BIND_VIEW" /> - <field name="MOVE_FROM_ACTIVE_TO_SCRAP_HEAP" /> - <field name="MOVE_TO_ACTIVE_HEAP" /> - <field name="MOVE_TO_SCRAP_HEAP" /> - <field name="NEW_VIEW" /> - <field name="RECYCLE_FROM_ACTIVE_HEAP" /> - <field name="RECYCLE_FROM_SCRAP_HEAP" /> - </class> - <class name="android/webkit/ConsoleMessage$MessageLevel" since="8"> - <extends name="java/lang/Enum" /> - <field name="DEBUG" /> - <field name="ERROR" /> - <field name="LOG" /> - <field name="TIP" /> - <field name="WARNING" /> - </class> - <class name="android/webkit/WebSettings$LayoutAlgorithm" since="1"> - <extends name="java/lang/Enum" /> - <field name="NARROW_COLUMNS" /> - <field name="NORMAL" /> - <field name="SINGLE_COLUMN" /> - </class> - <class name="android/webkit/WebSettings$PluginState" since="8"> - <extends name="java/lang/Enum" /> - <field name="OFF" /> - <field name="ON" /> - <field name="ON_DEMAND" /> - </class> - <class name="android/webkit/WebSettings$RenderPriority" since="1"> - <extends name="java/lang/Enum" /> - <field name="HIGH" /> - <field name="LOW" /> - <field name="NORMAL" /> - </class> - <class name="android/webkit/WebSettings$TextSize" since="1"> - <extends name="java/lang/Enum" /> - <field name="LARGER" /> - <field name="LARGEST" /> - <field name="NORMAL" /> - <field name="SMALLER" /> - <field name="SMALLEST" /> - </class> - <class name="android/webkit/WebSettings$ZoomDensity" since="7"> - <extends name="java/lang/Enum" /> - <field name="CLOSE" /> - <field name="FAR" /> - <field name="MEDIUM" /> - </class> - <class name="android/widget/ImageView$ScaleType" since="1"> - <extends name="java/lang/Enum" /> - <field name="CENTER" /> - <field name="CENTER_CROP" /> - <field name="CENTER_INSIDE" /> - <field name="FIT_CENTER" /> - <field name="FIT_END" /> - <field name="FIT_START" /> - <field name="FIT_XY" /> - <field name="MATRIX" /> - </class> - <class name="android/widget/TextView$BufferType" since="1"> - <extends name="java/lang/Enum" /> - <field name="EDITABLE" /> - <field name="NORMAL" /> - <field name="SPANNABLE" /> - </class> - <class name="com/google/android/maps/MapView$ReticleDrawMode" since="1"> - <extends name="java/lang/Enum" /> - <field name="DRAW_RETICLE_NEVER" /> - <field name="DRAW_RETICLE_OVER" /> - <field name="DRAW_RETICLE_UNDER" /> - </class> - <class name="java/lang/Thread$State" since="1"> - <extends name="java/lang/Enum" /> - <field name="BLOCKED" /> - <field name="NEW" /> - <field name="RUNNABLE" /> - <field name="TERMINATED" /> - <field name="TIMED_WAITING" /> - <field name="WAITING" /> - </class> - <class name="java/lang/annotation/ElementType" since="1"> - <extends name="java/lang/Enum" /> - <field name="ANNOTATION_TYPE" /> - <field name="CONSTRUCTOR" /> - <field name="FIELD" /> - <field name="LOCAL_VARIABLE" /> - <field name="METHOD" /> - <field name="PACKAGE" /> - <field name="PARAMETER" /> - <field name="TYPE" /> - </class> - <class name="java/lang/annotation/RetentionPolicy" since="1"> - <extends name="java/lang/Enum" /> - <field name="CLASS" /> - <field name="RUNTIME" /> - <field name="SOURCE" /> - </class> - <class name="java/math/RoundingMode" since="1"> - <extends name="java/lang/Enum" /> - <field name="CEILING" /> - <field name="DOWN" /> - <field name="FLOOR" /> - <field name="HALF_DOWN" /> - <field name="HALF_EVEN" /> - <field name="HALF_UP" /> - <field name="UNNECESSARY" /> - <field name="UP" /> - </class> - <class name="java/net/Authenticator$RequestorType" since="1"> - <extends name="java/lang/Enum" /> - <field name="PROXY" /> - <field name="SERVER" /> - </class> - <class name="java/net/Proxy$Type" since="1"> - <extends name="java/lang/Enum" /> - <field name="DIRECT" /> - <field name="HTTP" /> - <field name="SOCKS" /> - </class> - <class name="java/security/KeyRep$Type" since="1"> - <extends name="java/lang/Enum" /> - <field name="PRIVATE" /> - <field name="PUBLIC" /> - <field name="SECRET" /> - </class> - <class name="java/sql/ClientInfoStatus" since="9"> - <extends name="java/lang/Enum" /> - <field name="REASON_UNKNOWN" /> - <field name="REASON_UNKNOWN_PROPERTY" /> - <field name="REASON_VALUE_INVALID" /> - <field name="REASON_VALUE_TRUNCATED" /> - </class> - <class name="java/sql/RowIdLifetime" since="9"> - <extends name="java/lang/Enum" /> - <field name="ROWID_UNSUPPORTED" /> - <field name="ROWID_VALID_FOREVER" /> - <field name="ROWID_VALID_OTHER" /> - <field name="ROWID_VALID_SESSION" /> - <field name="ROWID_VALID_TRANSACTION" /> - </class> - <class name="java/text/Normalizer$Form" since="9"> - <extends name="java/lang/Enum" /> - <field name="NFC" /> - <field name="NFD" /> - <field name="NFKC" /> - <field name="NFKD" /> - </class> - <class name="java/util/Formatter$BigDecimalLayoutForm" since="1"> - <extends name="java/lang/Enum" /> - <field name="DECIMAL_FLOAT" /> - <field name="SCIENTIFIC" /> - </class> - <class name="java/util/concurrent/TimeUnit" since="1"> - <extends name="java/lang/Enum" /> - <field name="DAYS" since="9" /> - <field name="HOURS" since="9" /> - <field name="MICROSECONDS" /> - <field name="MILLISECONDS" /> - <field name="MINUTES" since="9" /> - <field name="NANOSECONDS" /> - <field name="SECONDS" /> - </class> - <class name="javax/net/ssl/SSLEngineResult$HandshakeStatus" since="1"> - <extends name="java/lang/Enum" /> - <field name="FINISHED" /> - <field name="NEED_TASK" /> - <field name="NEED_UNWRAP" /> - <field name="NEED_WRAP" /> - <field name="NOT_HANDSHAKING" /> - </class> - <class name="javax/net/ssl/SSLEngineResult$Status" since="1"> - <extends name="java/lang/Enum" /> - <field name="BUFFER_OVERFLOW" /> - <field name="BUFFER_UNDERFLOW" /> - <field name="CLOSED" /> - <field name="OK" /> - </class> - <class name="org/apache/http/conn/routing/RouteInfo$LayerType" since="1"> - <extends name="java/lang/Enum" /> - <field name="LAYERED" /> - <field name="PLAIN" /> - </class> - <class name="org/apache/http/conn/routing/RouteInfo$TunnelType" since="1"> - <extends name="java/lang/Enum" /> - <field name="PLAIN" /> - <field name="TUNNELLED" /> - </class> -</api> diff --git a/common/src/com/android/annotations/NonNull.java b/common/src/com/android/annotations/NonNull.java index e306a31..973ebb6 100644 --- a/common/src/com/android/annotations/NonNull.java +++ b/common/src/com/android/annotations/NonNull.java @@ -32,7 +32,7 @@ import java.lang.annotation.Target; * This is a marker annotation and it has no specific attributes. */ @Documented -@Retention(RetentionPolicy.SOURCE) +@Retention(RetentionPolicy.CLASS) @Target({METHOD,PARAMETER,LOCAL_VARIABLE,FIELD}) public @interface NonNull { } diff --git a/common/src/com/android/annotations/NonNullByDefault.java b/common/src/com/android/annotations/NonNullByDefault.java index 23903d1..3db891c 100644 --- a/common/src/com/android/annotations/NonNullByDefault.java +++ b/common/src/com/android/annotations/NonNullByDefault.java @@ -41,7 +41,7 @@ import java.lang.annotation.Target; * This is a marker annotation and it has no specific attributes. */ @Documented -@Retention(RetentionPolicy.SOURCE) +@Retention(RetentionPolicy.CLASS) @Target({PACKAGE, TYPE}) public @interface NonNullByDefault { } diff --git a/common/src/com/android/annotations/Nullable.java b/common/src/com/android/annotations/Nullable.java index 376c1f6..d9c3861 100755 --- a/common/src/com/android/annotations/Nullable.java +++ b/common/src/com/android/annotations/Nullable.java @@ -43,7 +43,7 @@ import java.lang.annotation.Target; * This is a marker annotation and it has no specific attributes. */ @Documented -@Retention(RetentionPolicy.SOURCE) +@Retention(RetentionPolicy.CLASS) @Target({METHOD, PARAMETER, LOCAL_VARIABLE, FIELD}) public @interface Nullable { } diff --git a/common/src/com/android/util/PositionXmlParser.java b/common/src/com/android/util/PositionXmlParser.java index 052348d..6eee96f 100644 --- a/common/src/com/android/util/PositionXmlParser.java +++ b/common/src/com/android/util/PositionXmlParser.java @@ -677,7 +677,7 @@ public class PositionXmlParser { } @Override - public void setEnd(Position end) { + public void setEnd(@NonNull Position end) { mEnd = end; } } diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/EmulatorConsole.java b/ddms/libs/ddmlib/src/com/android/ddmlib/EmulatorConsole.java index f3ab28c..2f4175f 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/EmulatorConsole.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/EmulatorConsole.java @@ -532,9 +532,13 @@ public final class EmulatorConsole { // need to make sure the string format uses dot and not comma Formatter formatter = new Formatter(Locale.US); - formatter.format(COMMAND_GPS, longitude, latitude, elevation); + try { + formatter.format(COMMAND_GPS, longitude, latitude, elevation); - return processCommand(formatter.toString()); + return processCommand(formatter.toString()); + } finally { + formatter.close(); + } } /** diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/SyncService.java b/ddms/libs/ddmlib/src/com/android/ddmlib/SyncService.java index bf0b4e1..f207567 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/SyncService.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/SyncService.java @@ -523,51 +523,55 @@ public final class SyncService { FileOutputStream fos = null; try { fos = new FileOutputStream(f); - } catch (IOException e) { - Log.e("ddms", String.format("Failed to open local file %s for writing, Reason: %s", - f.getAbsolutePath(), e.toString())); - throw new SyncException(SyncError.FILE_WRITE_ERROR); - } - // the buffer to read the data - byte[] data = new byte[SYNC_DATA_MAX]; + // the buffer to read the data + byte[] data = new byte[SYNC_DATA_MAX]; - // loop to get data until we're done. - while (true) { - // check if we're cancelled - if (monitor.isCanceled() == true) { - throw new SyncException(SyncError.CANCELED); - } + // loop to get data until we're done. + while (true) { + // check if we're cancelled + if (monitor.isCanceled() == true) { + throw new SyncException(SyncError.CANCELED); + } - // if we're done, we stop the loop - if (checkResult(pullResult, ID_DONE)) { - break; - } - if (checkResult(pullResult, ID_DATA) == false) { - // hmm there's an error - throw new SyncException(SyncError.TRANSFER_PROTOCOL_ERROR, - readErrorMessage(pullResult, timeOut)); - } - int length = ArrayHelper.swap32bitFromArray(pullResult, 4); - if (length > SYNC_DATA_MAX) { - // buffer overrun! - // error and exit - throw new SyncException(SyncError.BUFFER_OVERRUN); - } + // if we're done, we stop the loop + if (checkResult(pullResult, ID_DONE)) { + break; + } + if (checkResult(pullResult, ID_DATA) == false) { + // hmm there's an error + throw new SyncException(SyncError.TRANSFER_PROTOCOL_ERROR, + readErrorMessage(pullResult, timeOut)); + } + int length = ArrayHelper.swap32bitFromArray(pullResult, 4); + if (length > SYNC_DATA_MAX) { + // buffer overrun! + // error and exit + throw new SyncException(SyncError.BUFFER_OVERRUN); + } - // now read the length we received - AdbHelper.read(mChannel, data, length, timeOut); + // now read the length we received + AdbHelper.read(mChannel, data, length, timeOut); - // get the header for the next packet. - AdbHelper.read(mChannel, pullResult, -1, timeOut); + // get the header for the next packet. + AdbHelper.read(mChannel, pullResult, -1, timeOut); - // write the content in the file - fos.write(data, 0, length); + // write the content in the file + fos.write(data, 0, length); - monitor.advance(length); - } + monitor.advance(length); + } - fos.flush(); + fos.flush(); + } catch (IOException e) { + Log.e("ddms", String.format("Failed to open local file %s for writing, Reason: %s", + f.getAbsolutePath(), e.toString())); + throw new SyncException(SyncError.FILE_WRITE_ERROR); + } finally { + if (fos != null) { + fos.close(); + } + } } @@ -637,48 +641,51 @@ public final class SyncService { // create the header for the action msg = createSendFileReq(ID_SEND, remotePathContent, 0644); - } catch (UnsupportedEncodingException e) { - throw new SyncException(SyncError.REMOTE_PATH_ENCODING, e); - } - - // and send it. We use a custom try/catch block to make the difference between - // file and network IO exceptions. - AdbHelper.write(mChannel, msg, -1, timeOut); - // create the buffer used to read. - // we read max SYNC_DATA_MAX, but we need 2 4 bytes at the beginning. - if (mBuffer == null) { - mBuffer = new byte[SYNC_DATA_MAX + 8]; - } - System.arraycopy(ID_DATA, 0, mBuffer, 0, ID_DATA.length); + // and send it. We use a custom try/catch block to make the difference between + // file and network IO exceptions. + AdbHelper.write(mChannel, msg, -1, timeOut); - // look while there is something to read - while (true) { - // check if we're canceled - if (monitor.isCanceled() == true) { - throw new SyncException(SyncError.CANCELED); + // create the buffer used to read. + // we read max SYNC_DATA_MAX, but we need 2 4 bytes at the beginning. + if (mBuffer == null) { + mBuffer = new byte[SYNC_DATA_MAX + 8]; } + System.arraycopy(ID_DATA, 0, mBuffer, 0, ID_DATA.length); - // read up to SYNC_DATA_MAX - int readCount = fis.read(mBuffer, 8, SYNC_DATA_MAX); + // look while there is something to read + while (true) { + // check if we're canceled + if (monitor.isCanceled() == true) { + throw new SyncException(SyncError.CANCELED); + } - if (readCount == -1) { - // we reached the end of the file - break; - } + // read up to SYNC_DATA_MAX + int readCount = fis.read(mBuffer, 8, SYNC_DATA_MAX); - // now send the data to the device - // first write the amount read - ArrayHelper.swap32bitsToArray(readCount, mBuffer, 4); + if (readCount == -1) { + // we reached the end of the file + break; + } - // now write it - AdbHelper.write(mChannel, mBuffer, readCount+8, timeOut); + // now send the data to the device + // first write the amount read + ArrayHelper.swap32bitsToArray(readCount, mBuffer, 4); - // and advance the monitor - monitor.advance(readCount); + // now write it + AdbHelper.write(mChannel, mBuffer, readCount+8, timeOut); + + // and advance the monitor + monitor.advance(readCount); + } + } catch (UnsupportedEncodingException e) { + throw new SyncException(SyncError.REMOTE_PATH_ENCODING, e); + } finally { + // close the local file + if (fis != null) { + fis.close(); + } } - // close the local file - fis.close(); // create the DONE message long time = System.currentTimeMillis() / 1000; diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/log/EventLogParser.java b/ddms/libs/ddmlib/src/com/android/ddmlib/log/EventLogParser.java index 22c0703..b2d8256 100644 --- a/ddms/libs/ddmlib/src/com/android/ddmlib/log/EventLogParser.java +++ b/ddms/libs/ddmlib/src/com/android/ddmlib/log/EventLogParser.java @@ -124,8 +124,9 @@ public final class EventLogParser { * @return <code>true</code> if success, <code>false</code> if failure. */ public boolean init(String filePath) { + BufferedReader reader = null; try { - BufferedReader reader = new BufferedReader(new FileReader(filePath)); + reader = new BufferedReader(new FileReader(filePath)); String line = null; do { @@ -138,6 +139,14 @@ public final class EventLogParser { return true; } catch (IOException e) { return false; + } finally { + try { + if (reader != null) { + reader.close(); + } + } catch (IOException e) { + // ignore + } } } diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/EventLogPanel.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/EventLogPanel.java index 4faac3a..937ee40 100644 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/EventLogPanel.java +++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/log/event/EventLogPanel.java @@ -914,10 +914,13 @@ public class EventLogPanel extends TablePanel implements ILogListener, byte[] buffer = new byte[256]; FileInputStream fis = new FileInputStream(fileName); - - int count; - while ((count = fis.read(buffer)) != -1) { - logReceiver.parseNewData(buffer, 0, count); + try { + int count; + while ((count = fis.read(buffer)) != -1) { + logReceiver.parseNewData(buffer, 0, count); + } + } finally { + fis.close(); } } diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogPanel.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogPanel.java index d60bae8..a347155 100644 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogPanel.java +++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/logcat/LogPanel.java @@ -730,8 +730,9 @@ public class LogPanel extends SelectionDependentPanel { Arrays.sort(selection); // loop on the selection and output the file. + FileWriter writer = null; try { - FileWriter writer = new FileWriter(fileName); + writer = new FileWriter(fileName); for (int i : selection) { TableItem item = currentTable.getItem(i); @@ -744,6 +745,14 @@ public class LogPanel extends SelectionDependentPanel { } catch (IOException e) { return false; + } finally { + if (writer != null) { + try { + writer.close(); + } catch (IOException e) { + // ignore + } + } } } } diff --git a/ddms/libs/ddmuilib/src/com/android/ddmuilib/net/NetworkPanel.java b/ddms/libs/ddmuilib/src/com/android/ddmuilib/net/NetworkPanel.java index f8cb7a3..febd99c 100644 --- a/ddms/libs/ddmuilib/src/com/android/ddmuilib/net/NetworkPanel.java +++ b/ddms/libs/ddmuilib/src/com/android/ddmuilib/net/NetworkPanel.java @@ -439,7 +439,9 @@ public class NetworkPanel extends TablePanel { } else { final int size = mTrackedItems.size(); item.color = nextSeriesColor(size); - item.label = "0x" + new Formatter().format("%08x", tag); + Formatter formatter = new Formatter(); + item.label = "0x" + formatter.format("%08x", tag); + formatter.close(); } // create color chip to display as legend in table diff --git a/eclipse/dictionary.txt b/eclipse/dictionary.txt index cbf3d10..dbb51e5 100644 --- a/eclipse/dictionary.txt +++ b/eclipse/dictionary.txt @@ -292,7 +292,9 @@ textfields thematically themed thumbnail +thumbnails timestamp +timestamps tmp toolbar tooltip diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/icons/lint1.png b/eclipse/plugins/com.android.ide.eclipse.adt/icons/lint1.png Binary files differindex aa6f067..f429164 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/icons/lint1.png +++ b/eclipse/plugins/com.android.ide.eclipse.adt/icons/lint1.png diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/AbsoluteLayoutRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/AbsoluteLayoutRule.java index 57406d5..d7adbae 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/AbsoluteLayoutRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/AbsoluteLayoutRule.java @@ -16,11 +16,13 @@ package com.android.ide.common.layout; -import static com.android.util.XmlUtils.ANDROID_URI; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_X; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_Y; import static com.android.ide.common.layout.LayoutConstants.VALUE_N_DP; +import static com.android.util.XmlUtils.ANDROID_URI; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.ide.common.api.DrawingStyle; import com.android.ide.common.api.DropFeedback; import com.android.ide.common.api.IDragElement; @@ -45,7 +47,7 @@ import java.util.Map; public class AbsoluteLayoutRule extends BaseLayoutRule { @Override - public List<String> getSelectionHint(INode parentNode, INode childNode) { + public List<String> getSelectionHint(@NonNull INode parentNode, @NonNull INode childNode) { List<String> infos = new ArrayList<String>(2); infos.add("AbsoluteLayout is deprecated."); infos.add("Use other layouts instead."); @@ -56,8 +58,8 @@ public class AbsoluteLayoutRule extends BaseLayoutRule { // The AbsoluteLayout accepts any drag'n'drop anywhere on its surface. @Override - public DropFeedback onDropEnter(INode targetNode, Object targetView, - final IDragElement[] elements) { + public DropFeedback onDropEnter(@NonNull INode targetNode, @Nullable Object targetView, + final @Nullable IDragElement[] elements) { if (elements.length == 0) { return null; @@ -65,7 +67,8 @@ public class AbsoluteLayoutRule extends BaseLayoutRule { DropFeedback df = new DropFeedback(null, new IFeedbackPainter() { @Override - public void paint(IGraphics gc, INode node, DropFeedback feedback) { + public void paint(@NonNull IGraphics gc, @NonNull INode node, + @NonNull DropFeedback feedback) { // Paint callback for the AbsoluteLayout. // This is called by the canvas when a draw is needed. drawFeedback(gc, node, elements, feedback); @@ -128,8 +131,8 @@ public class AbsoluteLayoutRule extends BaseLayoutRule { } @Override - public DropFeedback onDropMove(INode targetNode, IDragElement[] elements, - DropFeedback feedback, Point p) { + public DropFeedback onDropMove(@NonNull INode targetNode, @NonNull IDragElement[] elements, + @Nullable DropFeedback feedback, @NonNull Point p) { // Update the data used by the DropFeedback.paintCallback above. feedback.userData = p; feedback.requestPaint = true; @@ -138,13 +141,14 @@ public class AbsoluteLayoutRule extends BaseLayoutRule { } @Override - public void onDropLeave(INode targetNode, IDragElement[] elements, DropFeedback feedback) { + public void onDropLeave(@NonNull INode targetNode, @NonNull IDragElement[] elements, + @Nullable DropFeedback feedback) { // Nothing to do. } @Override - public void onDropped(final INode targetNode, final IDragElement[] elements, - final DropFeedback feedback, final Point p) { + public void onDropped(final @NonNull INode targetNode, final @NonNull IDragElement[] elements, + final @Nullable DropFeedback feedback, final @NonNull Point p) { final Rect b = targetNode.getBounds(); if (!b.isValid()) { @@ -158,7 +162,7 @@ public class AbsoluteLayoutRule extends BaseLayoutRule { targetNode.editXml("Add elements to AbsoluteLayout", new INodeHandler() { @Override - public void handle(INode node) { + public void handle(@NonNull INode node) { boolean first = true; Point offset = null; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/AdapterViewRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/AdapterViewRule.java index 5b23e34..28f5fc9 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/AdapterViewRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/AdapterViewRule.java @@ -15,6 +15,8 @@ */ package com.android.ide.common.layout; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.ide.common.api.DrawingStyle; import com.android.ide.common.api.DropFeedback; import com.android.ide.common.api.IDragElement; @@ -27,12 +29,14 @@ import com.android.ide.common.api.Rect; /** Rule for AdapterView subclasses that don't have more specific rules */ public class AdapterViewRule extends BaseLayoutRule { @Override - public DropFeedback onDropEnter(INode targetNode, Object targetView, IDragElement[] elements) { + public DropFeedback onDropEnter(@NonNull INode targetNode, @Nullable Object targetView, + @Nullable IDragElement[] elements) { // You are not allowed to insert children into AdapterViews; you must // use the dedicated addView methods etc dynamically DropFeedback dropFeedback = new DropFeedback(null, new IFeedbackPainter() { @Override - public void paint(IGraphics gc, INode node, DropFeedback feedback) { + public void paint(@NonNull IGraphics gc, @NonNull INode node, + @NonNull DropFeedback feedback) { Rect b = node.getBounds(); if (b.isValid()) { gc.useStyle(DrawingStyle.DROP_RECIPIENT); @@ -50,8 +54,8 @@ public class AdapterViewRule extends BaseLayoutRule { } @Override - public DropFeedback onDropMove(INode targetNode, IDragElement[] elements, - DropFeedback feedback, Point p) { + public DropFeedback onDropMove(@NonNull INode targetNode, @NonNull IDragElement[] elements, + @Nullable DropFeedback feedback, @NonNull Point p) { feedback.invalidTarget = true; return feedback; } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseLayoutRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseLayoutRule.java index 581788b..6f76b51 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseLayoutRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseLayoutRule.java @@ -16,7 +16,6 @@ package com.android.ide.common.layout; -import static com.android.util.XmlUtils.ANDROID_URI; import static com.android.ide.common.layout.LayoutConstants.ATTR_ID; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_ABOVE; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_ALIGN_BASELINE; @@ -52,7 +51,10 @@ import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_Y; import static com.android.ide.common.layout.LayoutConstants.VALUE_FILL_PARENT; import static com.android.ide.common.layout.LayoutConstants.VALUE_MATCH_PARENT; import static com.android.ide.common.layout.LayoutConstants.VALUE_WRAP_CONTENT; +import static com.android.util.XmlUtils.ANDROID_URI; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.ide.common.api.DrawingStyle; import com.android.ide.common.api.DropFeedback; import com.android.ide.common.api.IAttributeInfo; @@ -114,11 +116,13 @@ public class BaseLayoutRule extends BaseViewRule { IMenuCallback actionCallback = new IMenuCallback() { @Override - public void action(RuleAction action, List<? extends INode> selectedNodes, - final String valueId, final Boolean newValue) { + public void action(@NonNull RuleAction action, + @NonNull List<? extends INode> selectedNodes, + final @Nullable String valueId, + final @Nullable Boolean newValue) { parentNode.editXml("Change Margins", new INodeHandler() { @Override - public void handle(INode n) { + public void handle(@NonNull INode n) { String uri = ANDROID_URI; String all = first.getStringAttr(uri, ATTR_LAYOUT_MARGIN); String left = first.getStringAttr(uri, ATTR_LAYOUT_MARGIN_LEFT); @@ -154,8 +158,8 @@ public class BaseLayoutRule extends BaseViewRule { final INode first = targets.get(0); ChoiceProvider provider = new ChoiceProvider() { @Override - public void addChoices(List<String> titles, List<URL> iconUrls, - List<String> ids) { + public void addChoices(@NonNull List<String> titles, @NonNull List<URL> iconUrls, + @NonNull List<String> ids) { IAttributeInfo info = first.getAttributeInfo(ANDROID_URI, attributeName); if (info != null) { // Generate list of possible gravity value constants @@ -180,8 +184,10 @@ public class BaseLayoutRule extends BaseViewRule { } @Override - public void addLayoutActions(List<RuleAction> actions, final INode parentNode, - final List<? extends INode> children) { + public void addLayoutActions( + @NonNull List<RuleAction> actions, + final @NonNull INode parentNode, + final @NonNull List<? extends INode> children) { super.addLayoutActions(actions, parentNode, children); final List<? extends INode> targets = children == null || children.size() == 0 ? @@ -192,8 +198,11 @@ public class BaseLayoutRule extends BaseViewRule { // Shared action callback IMenuCallback actionCallback = new IMenuCallback() { @Override - public void action(RuleAction action, List<? extends INode> selectedNodes, - final String valueId, final Boolean newValue) { + public void action( + @NonNull RuleAction action, + @NonNull List<? extends INode> selectedNodes, + final @Nullable String valueId, + final @Nullable Boolean newValue) { final String actionId = action.getId(); final String undoLabel; if (actionId.equals(ACTION_FILL_WIDTH)) { @@ -205,7 +214,7 @@ public class BaseLayoutRule extends BaseViewRule { } parentNode.editXml(undoLabel, new INodeHandler() { @Override - public void handle(INode n) { + public void handle(@NonNull INode n) { String attribute = actionId.equals(ACTION_FILL_WIDTH) ? ATTR_LAYOUT_WIDTH : ATTR_LAYOUT_HEIGHT; String value; @@ -244,7 +253,8 @@ public class BaseLayoutRule extends BaseViewRule { * Derived layouts should override this behavior if not appropriate. */ @Override - public void onPaste(INode targetNode, Object targetView, IDragElement[] elements) { + public void onPaste(@NonNull INode targetNode, @Nullable Object targetView, + @NonNull IDragElement[] elements) { DropFeedback feedback = onDropEnter(targetNode, targetView, elements); if (feedback != null) { Point p = targetNode.getBounds().getTopLeft(); @@ -576,7 +586,7 @@ public class BaseLayoutRule extends BaseViewRule { targetNode.editXml("Insert Elements", new INodeHandler() { @Override - public void handle(INode node) { + public void handle(@NonNull INode node) { // Now write the new elements. int insertPos = initialInsertPos; for (IDragElement element : elements) { @@ -606,9 +616,9 @@ public class BaseLayoutRule extends BaseViewRule { } @Override - public DropFeedback onResizeBegin(INode child, INode parent, - SegmentType horizontalEdge, SegmentType verticalEdge, - Object childView, Object parentView) { + public DropFeedback onResizeBegin(@NonNull INode child, @NonNull INode parent, + @Nullable SegmentType horizontalEdge, @Nullable SegmentType verticalEdge, + @Nullable Object childView, @Nullable Object parentView) { ResizeState state = createResizeState(parent, parentView, child); state.horizontalEdgeType = horizontalEdge; state.verticalEdgeType = verticalEdge; @@ -618,7 +628,8 @@ public class BaseLayoutRule extends BaseViewRule { Map<INode, Rect> sizes = mRulesEngine.measureChildren(parent, new IClientRulesEngine.AttributeFilter() { @Override - public String getAttribute(INode node, String namespace, String localName) { + public String getAttribute(@NonNull INode node, @Nullable String namespace, + @NonNull String localName) { // Change attributes to wrap_content if (ATTR_LAYOUT_WIDTH.equals(localName) && SdkConstants.NS_RESOURCES.equals(namespace)) { @@ -638,7 +649,8 @@ public class BaseLayoutRule extends BaseViewRule { return new DropFeedback(state, new IFeedbackPainter() { @Override - public void paint(IGraphics gc, INode node, DropFeedback feedback) { + public void paint(@NonNull IGraphics gc, @NonNull INode node, + @NonNull DropFeedback feedback) { ResizeState resizeState = (ResizeState) feedback.userData; if (resizeState != null && resizeState.bounds != null) { paintResizeFeedback(gc, node, resizeState); @@ -737,8 +749,8 @@ public class BaseLayoutRule extends BaseViewRule { } @Override - public void onResizeUpdate(DropFeedback feedback, INode child, INode parent, - Rect newBounds, int modifierMask) { + public void onResizeUpdate(@Nullable DropFeedback feedback, @NonNull INode child, + @NonNull INode parent, @NonNull Rect newBounds, int modifierMask) { ResizeState state = (ResizeState) feedback.userData; state.bounds = newBounds; state.modifierMask = modifierMask; @@ -799,14 +811,14 @@ public class BaseLayoutRule extends BaseViewRule { } @Override - public void onResizeEnd(DropFeedback feedback, INode child, final INode parent, - final Rect newBounds) { + public void onResizeEnd(@Nullable DropFeedback feedback, @NonNull INode child, + final @NonNull INode parent, final @NonNull Rect newBounds) { final Rect oldBounds = child.getBounds(); if (oldBounds.w != newBounds.w || oldBounds.h != newBounds.h) { final ResizeState state = (ResizeState) feedback.userData; child.editXml("Resize", new INodeHandler() { @Override - public void handle(INode n) { + public void handle(@NonNull INode n) { setNewSizeBounds(state, n, parent, oldBounds, newBounds, state.horizontalEdgeType, state.verticalEdgeType); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseViewRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseViewRule.java index 507bed5..4cc5f5e 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseViewRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/BaseViewRule.java @@ -94,7 +94,7 @@ public class BaseViewRule extends AbstractViewRule { new HashMap<String, Map<String, Prop>>(); @Override - public boolean onInitialize(String fqcn, IClientRulesEngine engine) { + public boolean onInitialize(@NonNull String fqcn, @NonNull IClientRulesEngine engine) { this.mRulesEngine = engine; // This base rule can handle any class so we don't need to filter on @@ -124,7 +124,8 @@ public class BaseViewRule extends AbstractViewRule { * - List of all other simple toggle attributes. */ @Override - public void addContextMenuActions(List<RuleAction> actions, final INode selectedNode) { + public void addContextMenuActions(@NonNull List<RuleAction> actions, + final @NonNull INode selectedNode) { String width = null; String currentWidth = selectedNode.getStringAttr(ANDROID_URI, ATTR_LAYOUT_WIDTH); @@ -155,9 +156,9 @@ public class BaseViewRule extends AbstractViewRule { final IMenuCallback onChange = new IMenuCallback() { @Override public void action( - final RuleAction action, - final List<? extends INode> selectedNodes, - final String valueId, final Boolean newValue) { + final @NonNull RuleAction action, + final @NonNull List<? extends INode> selectedNodes, + final @Nullable String valueId, final @Nullable Boolean newValue) { String fullActionId = action.getId(); boolean isProp = fullActionId.startsWith(PROP_PREFIX); final String actionId = isProp ? @@ -425,14 +426,14 @@ public class BaseViewRule extends AbstractViewRule { onChange /*callback*/, null /*icon*/, 50, true /*supportsMultipleNodes*/, new ActionProvider() { @Override - public List<RuleAction> getNestedActions(INode node) { + public @NonNull List<RuleAction> getNestedActions(@NonNull INode node) { List<RuleAction> propertyActionTypes = new ArrayList<RuleAction>(); propertyActionTypes.add(RuleAction.createChoices( "recent", "Recent", //$NON-NLS-1$ onChange /*callback*/, null /*icon*/, 10, true /*supportsMultipleNodes*/, new ActionProvider() { @Override - public List<RuleAction> getNestedActions(INode n) { + public @NonNull List<RuleAction> getNestedActions(@NonNull INode n) { List<RuleAction> propertyActions = new ArrayList<RuleAction>(); addRecentPropertyActions(propertyActions, n, onChange); return propertyActions; @@ -449,7 +450,7 @@ public class BaseViewRule extends AbstractViewRule { onChange /*callback*/, null /*icon*/, 60, true /*supportsMultipleNodes*/, new ActionProvider() { @Override - public List<RuleAction> getNestedActions(INode n) { + public @NonNull List<RuleAction> getNestedActions(@NonNull INode n) { List<RuleAction> propertyActions = new ArrayList<RuleAction>(); addPropertyActions(propertyActions, n, onChange, null, true); return propertyActions; @@ -463,7 +464,7 @@ public class BaseViewRule extends AbstractViewRule { onChange /*callback*/, null /*icon*/, 80, true /*supportsMultipleNodes*/, new ActionProvider() { @Override - public List<RuleAction> getNestedActions(INode n) { + public @NonNull List<RuleAction> getNestedActions(@NonNull INode n) { List<RuleAction> propertyActions = new ArrayList<RuleAction>(); addPropertyActions(propertyActions, n, onChange, null, false); return propertyActions; @@ -527,7 +528,7 @@ public class BaseViewRule extends AbstractViewRule { onChange /*callback*/, null /*icon*/, sortPriority++, true /*supportsMultipleNodes*/, new ActionProvider() { @Override - public List<RuleAction> getNestedActions(INode n) { + public @NonNull List<RuleAction> getNestedActions(@NonNull INode n) { List<RuleAction> propertyActions = new ArrayList<RuleAction>(); addPropertyActions(propertyActions, n, onChange, definedBy, false); return propertyActions; @@ -744,7 +745,8 @@ public class BaseViewRule extends AbstractViewRule { */ private static ChoiceProvider BOOLEAN_CHOICE_PROVIDER = new ChoiceProvider() { @Override - public void addChoices(List<String> titles, List<URL> iconUrls, List<String> ids) { + public void addChoices(@NonNull List<String> titles, @NonNull List<URL> iconUrls, + @NonNull List<String> ids) { titles.add("True"); ids.add(TRUE_ID); @@ -772,7 +774,8 @@ public class BaseViewRule extends AbstractViewRule { } @Override - public void addChoices(List<String> titles, List<URL> iconUrls, List<String> ids) { + public void addChoices(@NonNull List<String> titles, @NonNull List<URL> iconUrls, + @NonNull List<String> ids) { for (Entry<String, String> entry : mProperty.getChoices().entrySet()) { ids.add(entry.getKey()); titles.add(entry.getValue()); @@ -888,7 +891,8 @@ public class BaseViewRule extends AbstractViewRule { * an indication of where to paste. */ @Override - public void onPaste(INode targetNode, Object targetView, IDragElement[] elements) { + public void onPaste(@NonNull INode targetNode, @Nullable Object targetView, + @NonNull IDragElement[] elements) { // INode parent = targetNode.getParent(); if (parent != null) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/CalendarViewRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/CalendarViewRule.java index c580d8a..c509b95 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/CalendarViewRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/CalendarViewRule.java @@ -16,10 +16,11 @@ package com.android.ide.common.layout; -import static com.android.util.XmlUtils.ANDROID_URI; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_HEIGHT; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_WIDTH; +import static com.android.util.XmlUtils.ANDROID_URI; +import com.android.annotations.NonNull; import com.android.ide.common.api.INode; import com.android.ide.common.api.IViewRule; import com.android.ide.common.api.InsertType; @@ -30,7 +31,8 @@ import com.android.ide.common.api.InsertType; public class CalendarViewRule extends BaseViewRule { @Override - public void onCreate(INode node, INode parent, InsertType insertType) { + public void onCreate(@NonNull INode node, @NonNull INode parent, + @NonNull InsertType insertType) { super.onCreate(node, parent, insertType); // CalendarViews need a lot of space, and the wrapping doesn't seem to work diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/DialerFilterRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/DialerFilterRule.java index e7a129b..86855ae 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/DialerFilterRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/DialerFilterRule.java @@ -16,13 +16,14 @@ package com.android.ide.common.layout; -import static com.android.util.XmlUtils.ANDROID_URI; import static com.android.ide.common.layout.LayoutConstants.ATTR_ID; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_BELOW; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_WIDTH; import static com.android.ide.common.layout.LayoutConstants.ATTR_TEXT; import static com.android.ide.common.layout.LayoutConstants.FQCN_EDIT_TEXT; +import static com.android.util.XmlUtils.ANDROID_URI; +import com.android.annotations.NonNull; import com.android.ide.common.api.INode; import com.android.ide.common.api.IViewRule; import com.android.ide.common.api.InsertType; @@ -33,7 +34,8 @@ import com.android.ide.common.api.InsertType; public class DialerFilterRule extends BaseViewRule { @Override - public void onCreate(INode node, INode parent, InsertType insertType) { + public void onCreate(@NonNull INode node, @NonNull INode parent, + @NonNull InsertType insertType) { super.onCreate(node, parent, insertType); // A DialerFilter requires a couple of nested EditTexts with fixed ids: diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/EditTextRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/EditTextRule.java index 875756b..dc60086 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/EditTextRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/EditTextRule.java @@ -16,10 +16,12 @@ package com.android.ide.common.layout; -import static com.android.util.XmlUtils.ANDROID_URI; import static com.android.ide.common.layout.LayoutConstants.ATTR_EMS; import static com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors.REQUEST_FOCUS; +import static com.android.util.XmlUtils.ANDROID_URI; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.ide.common.api.IMenuCallback; import com.android.ide.common.api.INode; import com.android.ide.common.api.INodeHandler; @@ -35,7 +37,8 @@ import java.util.List; public class EditTextRule extends BaseViewRule { @Override - public void onCreate(INode node, INode parent, InsertType insertType) { + public void onCreate(@NonNull INode node, @NonNull INode parent, + @NonNull InsertType insertType) { super.onCreate(node, parent, insertType); if (parent != null) { @@ -57,7 +60,8 @@ public class EditTextRule extends BaseViewRule { * Adds a "Request Focus" menu item. */ @Override - public void addContextMenuActions(List<RuleAction> actions, final INode selectedNode) { + public void addContextMenuActions(@NonNull List<RuleAction> actions, + final @NonNull INode selectedNode) { super.addContextMenuActions(actions, selectedNode); final boolean hasFocus = hasFocus(selectedNode); @@ -65,11 +69,14 @@ public class EditTextRule extends BaseViewRule { IMenuCallback onChange = new IMenuCallback() { @Override - public void action(RuleAction menuAction, List<? extends INode> selectedNodes, - String valueId, Boolean newValue) { + public void action( + @NonNull RuleAction menuAction, + @NonNull List<? extends INode> selectedNodes, + @Nullable String valueId, + @Nullable Boolean newValue) { selectedNode.editXml(label, new INodeHandler() { @Override - public void handle(INode node) { + public void handle(@NonNull INode node) { INode focus = findFocus(findRoot(node)); if (focus != null && focus.getParent() != null) { focus.getParent().removeChild(focus); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/FragmentRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/FragmentRule.java index fdef082..533795d 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/FragmentRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/FragmentRule.java @@ -15,9 +15,10 @@ */ package com.android.ide.common.layout; -import static com.android.util.XmlUtils.ANDROID_URI; import static com.android.ide.common.layout.LayoutConstants.ATTR_NAME; +import static com.android.util.XmlUtils.ANDROID_URI; +import com.android.annotations.NonNull; import com.android.ide.common.api.INode; import com.android.ide.common.api.IViewRule; import com.android.ide.common.api.InsertType; @@ -27,7 +28,8 @@ import com.android.ide.common.api.InsertType; */ public class FragmentRule extends BaseViewRule { @Override - public void onCreate(INode node, INode parent, InsertType insertType) { + public void onCreate(@NonNull INode node, @NonNull INode parent, + @NonNull InsertType insertType) { // When dropping a fragment tag, ask the user which layout to include. if (insertType == InsertType.CREATE) { // NOT InsertType.CREATE_PREVIEW String fqcn = mRulesEngine.displayFragmentSourceInput(); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/FrameLayoutRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/FrameLayoutRule.java index 8a93fef..bbe4f1d 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/FrameLayoutRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/FrameLayoutRule.java @@ -16,11 +16,13 @@ package com.android.ide.common.layout; -import static com.android.util.XmlUtils.ANDROID_URI; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_GRAVITY; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_HEIGHT; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_WIDTH; +import static com.android.util.XmlUtils.ANDROID_URI; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.ide.common.api.DrawingStyle; import com.android.ide.common.api.DropFeedback; import com.android.ide.common.api.IDragElement; @@ -50,15 +52,16 @@ public class FrameLayoutRule extends BaseLayoutRule { // The FrameLayout accepts any drag'n'drop anywhere on its surface. @Override - public DropFeedback onDropEnter(INode targetNode, Object targetView, - final IDragElement[] elements) { + public DropFeedback onDropEnter(@NonNull INode targetNode, @Nullable Object targetView, + final @Nullable IDragElement[] elements) { if (elements.length == 0) { return null; } return new DropFeedback(null, new IFeedbackPainter() { @Override - public void paint(IGraphics gc, INode node, DropFeedback feedback) { + public void paint(@NonNull IGraphics gc, @NonNull INode node, + @NonNull DropFeedback feedback) { drawFeedback(gc, node, elements, feedback); } }); @@ -113,21 +116,22 @@ public class FrameLayoutRule extends BaseLayoutRule { } @Override - public DropFeedback onDropMove(INode targetNode, IDragElement[] elements, - DropFeedback feedback, Point p) { + public DropFeedback onDropMove(@NonNull INode targetNode, @NonNull IDragElement[] elements, + @Nullable DropFeedback feedback, @NonNull Point p) { feedback.userData = p; feedback.requestPaint = true; return feedback; } @Override - public void onDropLeave(INode targetNode, IDragElement[] elements, DropFeedback feedback) { + public void onDropLeave(@NonNull INode targetNode, @NonNull IDragElement[] elements, + @Nullable DropFeedback feedback) { // ignore } @Override - public void onDropped(final INode targetNode, final IDragElement[] elements, - final DropFeedback feedback, final Point p) { + public void onDropped(final @NonNull INode targetNode, final @NonNull IDragElement[] elements, + final @Nullable DropFeedback feedback, final @NonNull Point p) { Rect b = targetNode.getBounds(); if (!b.isValid()) { return; @@ -141,7 +145,7 @@ public class FrameLayoutRule extends BaseLayoutRule { targetNode.editXml("Add elements to FrameLayout", new INodeHandler() { @Override - public void handle(INode node) { + public void handle(@NonNull INode node) { // Now write the new elements. for (IDragElement element : elements) { @@ -159,8 +163,10 @@ public class FrameLayoutRule extends BaseLayoutRule { } @Override - public void addLayoutActions(List<RuleAction> actions, final INode parentNode, - final List<? extends INode> children) { + public void addLayoutActions( + @NonNull List<RuleAction> actions, + final @NonNull INode parentNode, + final @NonNull List<? extends INode> children) { super.addLayoutActions(actions, parentNode, children); actions.add(RuleAction.createSeparator(25)); actions.add(createMarginAction(parentNode, children)); @@ -170,7 +176,8 @@ public class FrameLayoutRule extends BaseLayoutRule { } @Override - public void onChildInserted(INode node, INode parent, InsertType insertType) { + public void onChildInserted(@NonNull INode node, @NonNull INode parent, + @NonNull InsertType insertType) { // Look at the fill preferences and fill embedded layouts etc String fqcn = node.getFqcn(); IViewMetadata metadata = mRulesEngine.getMetadata(fqcn); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/GridLayoutRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/GridLayoutRule.java index c51d229..a737251 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/GridLayoutRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/GridLayoutRule.java @@ -16,7 +16,6 @@ package com.android.ide.common.layout; -import static com.android.util.XmlUtils.ANDROID_URI; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_COLUMN; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_GRAVITY; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_ROW; @@ -30,7 +29,10 @@ import static com.android.ide.common.layout.LayoutConstants.GRAVITY_VALUE_FILL_V import static com.android.ide.common.layout.LayoutConstants.GRAVITY_VALUE_LEFT; import static com.android.ide.common.layout.LayoutConstants.VALUE_HORIZONTAL; import static com.android.ide.common.layout.LayoutConstants.VALUE_TRUE; +import static com.android.util.XmlUtils.ANDROID_URI; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.ide.common.api.DrawingStyle; import com.android.ide.common.api.DropFeedback; import com.android.ide.common.api.IDragElement; @@ -148,8 +150,10 @@ public class GridLayoutRule extends BaseLayoutRule { } @Override - public void addLayoutActions(List<RuleAction> actions, final INode parentNode, - final List<? extends INode> children) { + public void addLayoutActions( + @NonNull List<RuleAction> actions, + final @NonNull INode parentNode, + final @NonNull List<? extends INode> children) { super.addLayoutActions(actions, parentNode, children); String namespace = getNamespace(parentNode); @@ -174,11 +178,14 @@ public class GridLayoutRule extends BaseLayoutRule { IMenuCallback actionCallback = new IMenuCallback() { @Override - public void action(final RuleAction action, List<? extends INode> selectedNodes, - final String valueId, final Boolean newValue) { + public void action( + final @NonNull RuleAction action, + @NonNull List<? extends INode> selectedNodes, + final @Nullable String valueId, + final @Nullable Boolean newValue) { parentNode.editXml("Add/Remove Row/Column", new INodeHandler() { @Override - public void handle(INode n) { + public void handle(@NonNull INode n) { String id = action.getId(); if (id.equals(ACTION_SHOW_STRUCTURE)) { sShowStructure = !sShowStructure; @@ -268,15 +275,16 @@ public class GridLayoutRule extends BaseLayoutRule { } @Override - public DropFeedback onDropEnter(INode targetNode, Object targetView, IDragElement[] elements) { + public DropFeedback onDropEnter(@NonNull INode targetNode, @Nullable Object targetView, + @Nullable IDragElement[] elements) { GridDropHandler userData = new GridDropHandler(this, targetNode, targetView); IFeedbackPainter painter = GridLayoutPainter.createDropFeedbackPainter(this, elements); return new DropFeedback(userData, painter); } @Override - public DropFeedback onDropMove(INode targetNode, IDragElement[] elements, - DropFeedback feedback, Point p) { + public DropFeedback onDropMove(@NonNull INode targetNode, @NonNull IDragElement[] elements, + @Nullable DropFeedback feedback, @NonNull Point p) { feedback.requestPaint = true; GridDropHandler handler = (GridDropHandler) feedback.userData; @@ -286,8 +294,8 @@ public class GridLayoutRule extends BaseLayoutRule { } @Override - public void onDropped(final INode targetNode, final IDragElement[] elements, - DropFeedback feedback, Point p) { + public void onDropped(final @NonNull INode targetNode, final @NonNull IDragElement[] elements, + @Nullable DropFeedback feedback, @NonNull Point p) { Rect b = targetNode.getBounds(); if (!b.isValid()) { return; @@ -319,7 +327,8 @@ public class GridLayoutRule extends BaseLayoutRule { } @Override - public void onChildInserted(INode node, INode parent, InsertType insertType) { + public void onChildInserted(@NonNull INode node, @NonNull INode parent, + @NonNull InsertType insertType) { if (insertType == InsertType.MOVE_WITHIN) { // Don't adjust widths/heights/weights when just moving within a single layout return; @@ -386,7 +395,7 @@ public class GridLayoutRule extends BaseLayoutRule { } @Override - public void onRemovingChildren(List<INode> deleted, INode parent) { + public void onRemovingChildren(@NonNull List<INode> deleted, @NonNull INode parent) { super.onRemovingChildren(deleted, parent); // Attempt to clean up spacer objects for any newly-empty rows or columns @@ -521,8 +530,8 @@ public class GridLayoutRule extends BaseLayoutRule { } @Override - public void paintSelectionFeedback(IGraphics graphics, INode parentNode, - List<? extends INode> childNodes, Object view) { + public void paintSelectionFeedback(@NonNull IGraphics graphics, @NonNull INode parentNode, + @NonNull List<? extends INode> childNodes, @Nullable Object view) { super.paintSelectionFeedback(graphics, parentNode, childNodes, view); if (sShowStructure) { @@ -569,7 +578,10 @@ public class GridLayoutRule extends BaseLayoutRule { * approach #3 above. */ @Override - public void onPaste(INode targetNode, Object targetView, IDragElement[] elements) { + public void onPaste( + @NonNull INode targetNode, + @Nullable Object targetView, + @NonNull IDragElement[] elements) { DropFeedback feedback = onDropEnter(targetNode, targetView, elements); if (feedback != null) { Rect b = targetNode.getBounds(); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/GridViewRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/GridViewRule.java index bc3de5e..7eb3474 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/GridViewRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/GridViewRule.java @@ -16,10 +16,11 @@ package com.android.ide.common.layout; -import static com.android.util.XmlUtils.ANDROID_URI; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_WIDTH; import static com.android.ide.common.layout.LayoutConstants.ATTR_NUM_COLUMNS; +import static com.android.util.XmlUtils.ANDROID_URI; +import com.android.annotations.NonNull; import com.android.ide.common.api.INode; import com.android.ide.common.api.IViewRule; import com.android.ide.common.api.InsertType; @@ -30,7 +31,8 @@ import com.android.ide.common.api.InsertType; public class GridViewRule extends BaseViewRule { @Override - public void onCreate(INode node, INode parent, InsertType insertType) { + public void onCreate(@NonNull INode node, @NonNull INode parent, + @NonNull InsertType insertType) { super.onCreate(node, parent, insertType); node.setAttribute(ANDROID_URI, ATTR_LAYOUT_WIDTH, getFillParentValueName()); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/HorizontalScrollViewRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/HorizontalScrollViewRule.java index b2ea435..e7be263 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/HorizontalScrollViewRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/HorizontalScrollViewRule.java @@ -16,13 +16,15 @@ package com.android.ide.common.layout; -import static com.android.util.XmlUtils.ANDROID_URI; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_HEIGHT; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_WIDTH; import static com.android.ide.common.layout.LayoutConstants.ATTR_ORIENTATION; import static com.android.ide.common.layout.LayoutConstants.FQCN_LINEAR_LAYOUT; import static com.android.ide.common.layout.LayoutConstants.VALUE_HORIZONTAL; +import static com.android.util.XmlUtils.ANDROID_URI; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.ide.common.api.DrawingStyle; import com.android.ide.common.api.DropFeedback; import com.android.ide.common.api.IDragElement; @@ -39,7 +41,8 @@ import com.android.ide.common.api.Rect; public class HorizontalScrollViewRule extends FrameLayoutRule { @Override - public void onChildInserted(INode child, INode parent, InsertType insertType) { + public void onChildInserted(@NonNull INode child, @NonNull INode parent, + @NonNull InsertType insertType) { super.onChildInserted(child, parent, insertType); // The child of the ScrollView should fill in both directions @@ -49,7 +52,8 @@ public class HorizontalScrollViewRule extends FrameLayoutRule { } @Override - public void onCreate(INode node, INode parent, InsertType insertType) { + public void onCreate(@NonNull INode node, @NonNull INode parent, + @NonNull InsertType insertType) { super.onCreate(node, parent, insertType); if (insertType.isCreate()) { @@ -62,8 +66,8 @@ public class HorizontalScrollViewRule extends FrameLayoutRule { } @Override - public DropFeedback onDropMove(INode targetNode, IDragElement[] elements, - DropFeedback feedback, Point p) { + public DropFeedback onDropMove(@NonNull INode targetNode, @NonNull IDragElement[] elements, + @Nullable DropFeedback feedback, @NonNull Point p) { DropFeedback f = super.onDropMove(targetNode, elements, feedback, p); // HorizontalScrollViews only allow a single child diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/IgnoredLayoutRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/IgnoredLayoutRule.java index 999c6a0..3a65a86 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/IgnoredLayoutRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/IgnoredLayoutRule.java @@ -16,6 +16,8 @@ package com.android.ide.common.layout; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.ide.common.api.DropFeedback; import com.android.ide.common.api.IDragElement; import com.android.ide.common.api.INode; @@ -32,7 +34,8 @@ import com.android.ide.common.api.INode; */ public abstract class IgnoredLayoutRule extends BaseLayoutRule { @Override - public DropFeedback onDropEnter(INode targetNode, Object targetView, IDragElement[] elements) { + public DropFeedback onDropEnter(@NonNull INode targetNode, @Nullable Object targetView, + @Nullable IDragElement[] elements) { // Do nothing; this layout rule corresponds to a layout that // should not be handled as a layout by the visual editor - usually // because some widget is extending a layout for implementation purposes diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ImageButtonRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ImageButtonRule.java index e1afb56..364a3b6 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ImageButtonRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ImageButtonRule.java @@ -16,9 +16,10 @@ package com.android.ide.common.layout; -import static com.android.util.XmlUtils.ANDROID_URI; import static com.android.ide.common.layout.LayoutConstants.ATTR_SRC; +import static com.android.util.XmlUtils.ANDROID_URI; +import com.android.annotations.NonNull; import com.android.ide.common.api.INode; import com.android.ide.common.api.IViewRule; import com.android.ide.common.api.InsertType; @@ -29,7 +30,8 @@ import com.android.ide.common.api.InsertType; public class ImageButtonRule extends BaseViewRule { @Override - public void onCreate(INode node, INode parent, InsertType insertType) { + public void onCreate(@NonNull INode node, @NonNull INode parent, + @NonNull InsertType insertType) { super.onCreate(node, parent, insertType); // When dropping an include tag, ask the user which layout to include. diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ImageViewRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ImageViewRule.java index b255c14..08ef17c 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ImageViewRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ImageViewRule.java @@ -16,9 +16,10 @@ package com.android.ide.common.layout; -import static com.android.util.XmlUtils.ANDROID_URI; import static com.android.ide.common.layout.LayoutConstants.ATTR_SRC; +import static com.android.util.XmlUtils.ANDROID_URI; +import com.android.annotations.NonNull; import com.android.ide.common.api.INode; import com.android.ide.common.api.IViewRule; import com.android.ide.common.api.InsertType; @@ -29,7 +30,8 @@ import com.android.ide.common.api.InsertType; public class ImageViewRule extends BaseViewRule { @Override - public void onCreate(INode node, INode parent, InsertType insertType) { + public void onCreate(@NonNull INode node, @NonNull INode parent, + @NonNull InsertType insertType) { super.onCreate(node, parent, insertType); // When dropping an include tag, ask the user which layout to include. diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/IncludeRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/IncludeRule.java index a451257..978455a 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/IncludeRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/IncludeRule.java @@ -17,6 +17,7 @@ package com.android.ide.common.layout; import static com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors.ATTR_LAYOUT; +import com.android.annotations.NonNull; import com.android.ide.common.api.INode; import com.android.ide.common.api.IViewRule; import com.android.ide.common.api.InsertType; @@ -26,7 +27,8 @@ import com.android.ide.common.api.InsertType; */ public class IncludeRule extends BaseViewRule { @Override - public void onCreate(INode node, INode parent, InsertType insertType) { + public void onCreate(@NonNull INode node, @NonNull INode parent, + @NonNull InsertType insertType) { // When dropping an include tag, ask the user which layout to include. if (insertType == InsertType.CREATE) { // NOT InsertType.CREATE_PREVIEW String include = mRulesEngine.displayIncludeSourceInput(); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LinearLayoutRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LinearLayoutRule.java index 8f8ea02..04373e1 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LinearLayoutRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/LinearLayoutRule.java @@ -16,7 +16,6 @@ package com.android.ide.common.layout; -import static com.android.util.XmlUtils.ANDROID_URI; import static com.android.ide.common.layout.LayoutConstants.ATTR_BASELINE_ALIGNED; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_GRAVITY; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_HEIGHT; @@ -29,7 +28,10 @@ import static com.android.ide.common.layout.LayoutConstants.VALUE_HORIZONTAL; import static com.android.ide.common.layout.LayoutConstants.VALUE_VERTICAL; import static com.android.ide.common.layout.LayoutConstants.VALUE_WRAP_CONTENT; import static com.android.ide.common.layout.LayoutConstants.VALUE_ZERO_DP; +import static com.android.util.XmlUtils.ANDROID_URI; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.annotations.VisibleForTesting; import com.android.ide.common.api.DrawingStyle; import com.android.ide.common.api.DropFeedback; @@ -123,8 +125,10 @@ public class LinearLayoutRule extends BaseLayoutRule { } @Override - public void addLayoutActions(List<RuleAction> actions, final INode parentNode, - final List<? extends INode> children) { + public void addLayoutActions( + @NonNull List<RuleAction> actions, + final @NonNull INode parentNode, + final @NonNull List<? extends INode> children) { super.addLayoutActions(actions, parentNode, children); if (supportsOrientation()) { Choices action = RuleAction.createChoices( @@ -146,7 +150,7 @@ public class LinearLayoutRule extends BaseLayoutRule { if (!isVertical(parentNode)) { String current = parentNode.getStringAttr(ANDROID_URI, ATTR_BASELINE_ALIGNED); boolean isAligned = current == null || Boolean.valueOf(current); - actions.add(RuleAction.createToggle(null, "Toggle Baseline Alignment", + actions.add(RuleAction.createToggle(ACTION_BASELINE, "Toggle Baseline Alignment", isAligned, new PropertyCallback(Collections.singletonList(parentNode), "Change Baseline Alignment", @@ -167,11 +171,14 @@ public class LinearLayoutRule extends BaseLayoutRule { // Weights IMenuCallback actionCallback = new IMenuCallback() { @Override - public void action(final RuleAction action, List<? extends INode> selectedNodes, - final String valueId, final Boolean newValue) { + public void action( + final @NonNull RuleAction action, + @NonNull List<? extends INode> selectedNodes, + final @Nullable String valueId, + final @Nullable Boolean newValue) { parentNode.editXml("Change Weight", new INodeHandler() { @Override - public void handle(INode n) { + public void handle(@NonNull INode n) { String id = action.getId(); if (id.equals(ACTION_WEIGHT)) { String weight = @@ -266,8 +273,8 @@ public class LinearLayoutRule extends BaseLayoutRule { // ==== Drag'n'drop support ==== @Override - public DropFeedback onDropEnter(final INode targetNode, Object targetView, - final IDragElement[] elements) { + public DropFeedback onDropEnter(final @NonNull INode targetNode, @Nullable Object targetView, + final @Nullable IDragElement[] elements) { if (elements.length == 0) { return null; @@ -345,7 +352,8 @@ public class LinearLayoutRule extends BaseLayoutRule { new IFeedbackPainter() { @Override - public void paint(IGraphics gc, INode node, DropFeedback feedback) { + public void paint(@NonNull IGraphics gc, @NonNull INode node, + @NonNull DropFeedback feedback) { // Paint callback for the LinearLayout. This is called // by the canvas when a draw is needed. drawFeedback(gc, node, elements, feedback); @@ -466,8 +474,8 @@ public class LinearLayoutRule extends BaseLayoutRule { } @Override - public DropFeedback onDropMove(INode targetNode, IDragElement[] elements, - DropFeedback feedback, Point p) { + public DropFeedback onDropMove(@NonNull INode targetNode, @NonNull IDragElement[] elements, + @Nullable DropFeedback feedback, @NonNull Point p) { Rect b = targetNode.getBounds(); if (!b.isValid()) { return feedback; @@ -532,13 +540,14 @@ public class LinearLayoutRule extends BaseLayoutRule { } @Override - public void onDropLeave(INode targetNode, IDragElement[] elements, DropFeedback feedback) { + public void onDropLeave(@NonNull INode targetNode, @NonNull IDragElement[] elements, + @Nullable DropFeedback feedback) { // ignore } @Override - public void onDropped(final INode targetNode, final IDragElement[] elements, - final DropFeedback feedback, final Point p) { + public void onDropped(final @NonNull INode targetNode, final @NonNull IDragElement[] elements, + final @Nullable DropFeedback feedback, final @NonNull Point p) { LinearDropData data = (LinearDropData) feedback.userData; final int initialInsertPos = data.getInsertPos(); @@ -546,7 +555,8 @@ public class LinearLayoutRule extends BaseLayoutRule { } @Override - public void onChildInserted(INode node, INode parent, InsertType insertType) { + public void onChildInserted(@NonNull INode node, @NonNull INode parent, + @NonNull InsertType insertType) { if (insertType == InsertType.MOVE_WITHIN) { // Don't adjust widths/heights/weights when just moving within a single // LinearLayout @@ -775,7 +785,8 @@ public class LinearLayoutRule extends BaseLayoutRule { unweightedSizes = mRulesEngine.measureChildren(layout, new IClientRulesEngine.AttributeFilter() { @Override - public String getAttribute(INode n, String namespace, String localName) { + public String getAttribute(@NonNull INode n, @Nullable String namespace, + @NonNull String localName) { // Clear out layout weights; we need to measure the unweighted sizes // of the children if (ATTR_LAYOUT_WEIGHT.equals(localName) diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ListViewRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ListViewRule.java index 7420714..4088ab8 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ListViewRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ListViewRule.java @@ -16,9 +16,10 @@ package com.android.ide.common.layout; -import static com.android.util.XmlUtils.ANDROID_URI; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_WIDTH; +import static com.android.util.XmlUtils.ANDROID_URI; +import com.android.annotations.NonNull; import com.android.ide.common.api.INode; import com.android.ide.common.api.IViewRule; import com.android.ide.common.api.InsertType; @@ -32,7 +33,8 @@ import com.android.ide.common.api.InsertType; public class ListViewRule extends AdapterViewRule { @Override - public void onCreate(INode node, INode parent, InsertType insertType) { + public void onCreate(@NonNull INode node, @NonNull INode parent, + @NonNull InsertType insertType) { super.onCreate(node, parent, insertType); node.setAttribute(ANDROID_URI, ATTR_LAYOUT_WIDTH, getFillParentValueName()); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/MapViewRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/MapViewRule.java index b6d0ba2..c2e78a4 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/MapViewRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/MapViewRule.java @@ -18,6 +18,7 @@ package com.android.ide.common.layout; import static com.android.util.XmlUtils.ANDROID_URI; +import com.android.annotations.NonNull; import com.android.ide.common.api.INode; import com.android.ide.common.api.IViewRule; import com.android.ide.common.api.InsertType; @@ -31,7 +32,8 @@ import com.android.ide.common.api.InsertType; public class MapViewRule extends BaseViewRule { @Override - public void onCreate(INode node, INode parent, InsertType insertType) { + public void onCreate(@NonNull INode node, @NonNull INode parent, + @NonNull InsertType insertType) { super.onCreate(node, parent, insertType); if (insertType.isCreate()) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/MergeRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/MergeRule.java index 12358f9..9cef9c4 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/MergeRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/MergeRule.java @@ -16,6 +16,7 @@ package com.android.ide.common.layout; +import com.android.annotations.NonNull; import com.android.ide.common.api.INode; import com.android.ide.common.api.RuleAction; @@ -29,7 +30,8 @@ public class MergeRule extends FrameLayoutRule { // on top of each other at (0,0) @Override - public void addContextMenuActions(List<RuleAction> actions, final INode selectedNode) { + public void addContextMenuActions(@NonNull List<RuleAction> actions, + final @NonNull INode selectedNode) { // Deliberately ignore super.getContextMenu(); we don't want to attempt to list // properties for the <merge> tag } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/PropertyCallback.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/PropertyCallback.java index ac1635c..da2614e 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/PropertyCallback.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/PropertyCallback.java @@ -16,6 +16,8 @@ package com.android.ide.common.layout; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.ide.common.api.IMenuCallback; import com.android.ide.common.api.INode; import com.android.ide.common.api.INodeHandler; @@ -54,8 +56,8 @@ public class PropertyCallback implements IMenuCallback { // ---- Implements IMenuCallback ---- @Override - public void action(RuleAction action, List<? extends INode> selectedNodes, - final String valueId, final Boolean newValue) { + public void action(@NonNull RuleAction action, @NonNull List<? extends INode> selectedNodes, + final @Nullable String valueId, final @Nullable Boolean newValue) { if (mTargetNodes != null && mTargetNodes.size() > 0) { selectedNodes = mTargetNodes; } @@ -65,7 +67,7 @@ public class PropertyCallback implements IMenuCallback { final List<? extends INode> nodes = selectedNodes; selectedNodes.get(0).editXml(mUndoLabel, new INodeHandler() { @Override - public void handle(INode n) { + public void handle(@NonNull INode n) { for (INode targetNode : nodes) { if (valueId != null) { targetNode.setAttribute(mUri, mAttribute, valueId); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/PropertySettingNodeHandler.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/PropertySettingNodeHandler.java index ad3ddad..13c8842 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/PropertySettingNodeHandler.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/PropertySettingNodeHandler.java @@ -15,6 +15,7 @@ */ package com.android.ide.common.layout; +import com.android.annotations.NonNull; import com.android.ide.common.api.INode; import com.android.ide.common.api.INodeHandler; @@ -35,7 +36,7 @@ class PropertySettingNodeHandler implements INodeHandler { } @Override - public void handle(INode node) { + public void handle(@NonNull INode node) { node.setAttribute(mNamespaceUri, mAttribute, mValue); } }
\ No newline at end of file diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/QuickContactBadgeRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/QuickContactBadgeRule.java index f6372fd..0164794 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/QuickContactBadgeRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/QuickContactBadgeRule.java @@ -15,6 +15,7 @@ */ package com.android.ide.common.layout; +import com.android.annotations.NonNull; import com.android.ide.common.api.INode; import com.android.ide.common.api.IViewRule; import com.android.ide.common.api.InsertType; @@ -24,7 +25,8 @@ import com.android.ide.common.api.InsertType; */ public class QuickContactBadgeRule extends ImageViewRule { @Override - public void onCreate(INode node, INode parent, InsertType insertType) { + public void onCreate(@NonNull INode node, @NonNull INode parent, + @NonNull InsertType insertType) { // Deliberately override onCreate such that we don't populate a default // image; at design time layoutlib will supply the system default contacts // image. diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/RadioGroupRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/RadioGroupRule.java index 280019e..5ae0e92 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/RadioGroupRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/RadioGroupRule.java @@ -15,11 +15,12 @@ */ package com.android.ide.common.layout; -import static com.android.util.XmlUtils.ANDROID_URI; import static com.android.ide.common.layout.LayoutConstants.ATTR_CHECKED; import static com.android.ide.common.layout.LayoutConstants.ATTR_ID; import static com.android.ide.common.layout.LayoutConstants.VALUE_TRUE; +import static com.android.util.XmlUtils.ANDROID_URI; +import com.android.annotations.NonNull; import com.android.ide.common.api.INode; import com.android.ide.common.api.IViewRule; import com.android.ide.common.api.InsertType; @@ -30,7 +31,8 @@ import com.android.ide.common.api.InsertType; */ public class RadioGroupRule extends LinearLayoutRule { @Override - public void onCreate(INode node, INode parent, InsertType insertType) { + public void onCreate(@NonNull INode node, @NonNull INode parent, + @NonNull InsertType insertType) { super.onCreate(node, parent, insertType); if (insertType.isCreate()) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/RelativeLayoutRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/RelativeLayoutRule.java index f587bef..e9cd5d5 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/RelativeLayoutRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/RelativeLayoutRule.java @@ -16,7 +16,6 @@ package com.android.ide.common.layout; -import static com.android.util.XmlUtils.ANDROID_URI; import static com.android.ide.common.layout.LayoutConstants.ATTR_GRAVITY; import static com.android.ide.common.layout.LayoutConstants.ATTR_ID; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_ABOVE; @@ -40,7 +39,10 @@ import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_TO_RIGHT import static com.android.ide.common.layout.LayoutConstants.ID_PREFIX; import static com.android.ide.common.layout.LayoutConstants.NEW_ID_PREFIX; import static com.android.ide.common.layout.LayoutConstants.VALUE_TRUE; +import static com.android.util.XmlUtils.ANDROID_URI; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.ide.common.api.DropFeedback; import com.android.ide.common.api.IDragElement; import com.android.ide.common.api.IGraphics; @@ -93,7 +95,7 @@ public class RelativeLayoutRule extends BaseLayoutRule { // ==== Selection ==== @Override - public List<String> getSelectionHint(INode parentNode, INode childNode) { + public List<String> getSelectionHint(@NonNull INode parentNode, @NonNull INode childNode) { List<String> infos = new ArrayList<String>(18); addAttr(ATTR_LAYOUT_ABOVE, childNode, infos); addAttr(ATTR_LAYOUT_BELOW, childNode, infos); @@ -131,8 +133,8 @@ public class RelativeLayoutRule extends BaseLayoutRule { } @Override - public void paintSelectionFeedback(IGraphics graphics, INode parentNode, - List<? extends INode> childNodes, Object view) { + public void paintSelectionFeedback(@NonNull IGraphics graphics, @NonNull INode parentNode, + @NonNull List<? extends INode> childNodes, @Nullable Object view) { super.paintSelectionFeedback(graphics, parentNode, childNodes, view); boolean showDependents = true; @@ -150,14 +152,15 @@ public class RelativeLayoutRule extends BaseLayoutRule { // ==== Drag'n'drop support ==== @Override - public DropFeedback onDropEnter(INode targetNode, Object targetView, IDragElement[] elements) { + public DropFeedback onDropEnter(@NonNull INode targetNode, @Nullable Object targetView, + @Nullable IDragElement[] elements) { return new DropFeedback(new MoveHandler(targetNode, elements, mRulesEngine), new GuidelinePainter()); } @Override - public DropFeedback onDropMove(INode targetNode, IDragElement[] elements, - DropFeedback feedback, Point p) { + public DropFeedback onDropMove(@NonNull INode targetNode, @NonNull IDragElement[] elements, + @Nullable DropFeedback feedback, @NonNull Point p) { if (elements == null || elements.length == 0) { return null; } @@ -174,12 +177,13 @@ public class RelativeLayoutRule extends BaseLayoutRule { } @Override - public void onDropLeave(INode targetNode, IDragElement[] elements, DropFeedback feedback) { + public void onDropLeave(@NonNull INode targetNode, @NonNull IDragElement[] elements, + @Nullable DropFeedback feedback) { } @Override - public void onDropped(final INode targetNode, final IDragElement[] elements, - final DropFeedback feedback, final Point p) { + public void onDropped(final @NonNull INode targetNode, final @NonNull IDragElement[] elements, + final @Nullable DropFeedback feedback, final @NonNull Point p) { final MoveHandler state = (MoveHandler) feedback.userData; final Map<String, Pair<String, String>> idMap = getDropIdMap(targetNode, elements, @@ -187,7 +191,7 @@ public class RelativeLayoutRule extends BaseLayoutRule { targetNode.editXml("Dropped", new INodeHandler() { @Override - public void handle(INode n) { + public void handle(@NonNull INode n) { int index = -1; // Remove cycles @@ -235,7 +239,8 @@ public class RelativeLayoutRule extends BaseLayoutRule { } @Override - public void onChildInserted(INode node, INode parent, InsertType insertType) { + public void onChildInserted(@NonNull INode node, @NonNull INode parent, + @NonNull InsertType insertType) { // TODO: Handle more generically some way to ensure that widgets with no // intrinsic size get some minimum size until they are attached on multiple // opposing sides. @@ -246,7 +251,7 @@ public class RelativeLayoutRule extends BaseLayoutRule { } @Override - public void onRemovingChildren(List<INode> deleted, INode parent) { + public void onRemovingChildren(@NonNull List<INode> deleted, @NonNull INode parent) { super.onRemovingChildren(deleted, parent); // Remove any attachments pointing to the deleted nodes. @@ -286,29 +291,30 @@ public class RelativeLayoutRule extends BaseLayoutRule { // ==== Resize Support ==== @Override - public DropFeedback onResizeBegin(INode child, INode parent, - SegmentType horizontalEdgeType, SegmentType verticalEdgeType, - Object childView, Object parentView) { + public DropFeedback onResizeBegin(@NonNull INode child, @NonNull INode parent, + @Nullable SegmentType horizontalEdgeType, @Nullable SegmentType verticalEdgeType, + @Nullable Object childView, @Nullable Object parentView) { ResizeHandler state = new ResizeHandler(parent, child, mRulesEngine, horizontalEdgeType, verticalEdgeType); return new DropFeedback(state, new GuidelinePainter()); } @Override - public void onResizeUpdate(DropFeedback feedback, INode child, INode parent, Rect newBounds, + public void onResizeUpdate(@Nullable DropFeedback feedback, @NonNull INode child, + @NonNull INode parent, @NonNull Rect newBounds, int modifierMask) { ResizeHandler state = (ResizeHandler) feedback.userData; state.updateResize(feedback, child, newBounds, modifierMask); } @Override - public void onResizeEnd(DropFeedback feedback, INode child, INode parent, - final Rect newBounds) { + public void onResizeEnd(@Nullable DropFeedback feedback, @NonNull INode child, + @NonNull INode parent, final @NonNull Rect newBounds) { final ResizeHandler state = (ResizeHandler) feedback.userData; child.editXml("Resize", new INodeHandler() { @Override - public void handle(INode n) { + public void handle(@NonNull INode n) { state.removeCycles(); state.applyConstraints(n); } @@ -318,8 +324,10 @@ public class RelativeLayoutRule extends BaseLayoutRule { // ==== Layout Actions Bar ==== @Override - public void addLayoutActions(List<RuleAction> actions, final INode parentNode, - final List<? extends INode> children) { + public void addLayoutActions( + @NonNull List<RuleAction> actions, + final @NonNull INode parentNode, + final @NonNull List<? extends INode> children) { super.addLayoutActions(actions, parentNode, children); actions.add(createGravityAction(Collections.<INode>singletonList(parentNode), @@ -329,13 +337,15 @@ public class RelativeLayoutRule extends BaseLayoutRule { IMenuCallback callback = new IMenuCallback() { @Override - public void action(RuleAction action, List<? extends INode> selectedNodes, - final String valueId, final Boolean newValue) { + public void action(@NonNull RuleAction action, + @NonNull List<? extends INode> selectedNodes, + final @Nullable String valueId, + final @Nullable Boolean newValue) { final String id = action.getId(); if (id.equals(ACTION_CENTER_VERTICAL)|| id.equals(ACTION_CENTER_HORIZONTAL)) { parentNode.editXml("Center", new INodeHandler() { @Override - public void handle(INode n) { + public void handle(@NonNull INode n) { if (id.equals(ACTION_CENTER_VERTICAL)) { for (INode child : children) { centerVertically(child); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ScrollViewRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ScrollViewRule.java index 2114f39..1296c76 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ScrollViewRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ScrollViewRule.java @@ -16,11 +16,13 @@ package com.android.ide.common.layout; -import static com.android.util.XmlUtils.ANDROID_URI; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_HEIGHT; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_WIDTH; import static com.android.ide.common.layout.LayoutConstants.FQCN_LINEAR_LAYOUT; +import static com.android.util.XmlUtils.ANDROID_URI; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.ide.common.api.DrawingStyle; import com.android.ide.common.api.DropFeedback; import com.android.ide.common.api.IDragElement; @@ -37,7 +39,8 @@ import com.android.ide.common.api.Rect; public class ScrollViewRule extends FrameLayoutRule { @Override - public void onChildInserted(INode child, INode parent, InsertType insertType) { + public void onChildInserted(@NonNull INode child, @NonNull INode parent, + @NonNull InsertType insertType) { super.onChildInserted(child, parent, insertType); // The child of the ScrollView should fill in both directions @@ -47,7 +50,8 @@ public class ScrollViewRule extends FrameLayoutRule { } @Override - public void onCreate(INode node, INode parent, InsertType insertType) { + public void onCreate(@NonNull INode node, @NonNull INode parent, + @NonNull InsertType insertType) { super.onCreate(node, parent, insertType); if (insertType.isCreate()) { @@ -59,8 +63,8 @@ public class ScrollViewRule extends FrameLayoutRule { } @Override - public DropFeedback onDropMove(INode targetNode, IDragElement[] elements, - DropFeedback feedback, Point p) { + public DropFeedback onDropMove(@NonNull INode targetNode, @NonNull IDragElement[] elements, + @Nullable DropFeedback feedback, @NonNull Point p) { DropFeedback f = super.onDropMove(targetNode, elements, feedback, p); // ScrollViews only allow a single child diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/SeekBarRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/SeekBarRule.java index c65dec9..7c26859 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/SeekBarRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/SeekBarRule.java @@ -16,9 +16,10 @@ package com.android.ide.common.layout; -import static com.android.util.XmlUtils.ANDROID_URI; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_WIDTH; +import static com.android.util.XmlUtils.ANDROID_URI; +import com.android.annotations.NonNull; import com.android.ide.common.api.INode; import com.android.ide.common.api.IViewRule; import com.android.ide.common.api.InsertType; @@ -29,7 +30,8 @@ import com.android.ide.common.api.InsertType; public class SeekBarRule extends BaseViewRule { @Override - public void onCreate(INode node, INode parent, InsertType insertType) { + public void onCreate(@NonNull INode node, @NonNull INode parent, + @NonNull InsertType insertType) { super.onCreate(node, parent, insertType); // A SeekBar isn't useful with wrap_content because it packs itself down to diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/SlidingDrawerRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/SlidingDrawerRule.java index 73a5031..12ab448 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/SlidingDrawerRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/SlidingDrawerRule.java @@ -15,14 +15,15 @@ */ package com.android.ide.common.layout; -import static com.android.util.XmlUtils.ANDROID_URI; import static com.android.ide.common.layout.LayoutConstants.ATTR_CONTENT; import static com.android.ide.common.layout.LayoutConstants.ATTR_HANDLE; import static com.android.ide.common.layout.LayoutConstants.ATTR_ID; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_HEIGHT; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_WIDTH; import static com.android.ide.common.layout.LayoutConstants.ATTR_TEXT; +import static com.android.util.XmlUtils.ANDROID_URI; +import com.android.annotations.NonNull; import com.android.ide.common.api.INode; import com.android.ide.common.api.IViewRule; import com.android.ide.common.api.InsertType; @@ -34,7 +35,8 @@ import com.android.ide.common.api.InsertType; public class SlidingDrawerRule extends BaseLayoutRule { @Override - public void onCreate(INode node, INode parent, InsertType insertType) { + public void onCreate(@NonNull INode node, @NonNull INode parent, + @NonNull InsertType insertType) { super.onCreate(node, parent, insertType); if (insertType.isCreate()) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/TabHostRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/TabHostRule.java index 099a760..6724392 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/TabHostRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/TabHostRule.java @@ -16,7 +16,6 @@ package com.android.ide.common.layout; -import static com.android.util.XmlUtils.ANDROID_URI; import static com.android.ide.common.layout.LayoutConstants.ATTR_ID; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_HEIGHT; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_WIDTH; @@ -26,7 +25,9 @@ import static com.android.ide.common.layout.LayoutConstants.FQCN_LINEAR_LAYOUT; import static com.android.ide.common.layout.LayoutConstants.FQCN_TAB_WIDGET; import static com.android.ide.common.layout.LayoutConstants.VALUE_VERTICAL; import static com.android.ide.common.layout.LayoutConstants.VALUE_WRAP_CONTENT; +import static com.android.util.XmlUtils.ANDROID_URI; +import com.android.annotations.NonNull; import com.android.ide.common.api.INode; import com.android.ide.common.api.IViewRule; import com.android.ide.common.api.InsertType; @@ -40,7 +41,8 @@ public class TabHostRule extends IgnoredLayoutRule { // the child elements yourself, e.g. via addTab() etc. @Override - public void onCreate(INode node, INode parent, InsertType insertType) { + public void onCreate(@NonNull INode node, @NonNull INode parent, + @NonNull InsertType insertType) { super.onCreate(node, parent, insertType); if (insertType.isCreate()) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/TableLayoutRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/TableLayoutRule.java index ceb562d..b2cb1e4 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/TableLayoutRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/TableLayoutRule.java @@ -17,6 +17,8 @@ package com.android.ide.common.layout; import static com.android.ide.common.layout.LayoutConstants.FQCN_TABLE_ROW; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.ide.common.api.DropFeedback; import com.android.ide.common.api.IClientRulesEngine; import com.android.ide.common.api.IMenuCallback; @@ -60,7 +62,8 @@ public class TableLayoutRule extends LinearLayoutRule { } @Override - public void onChildInserted(INode child, INode parent, InsertType insertType) { + public void onChildInserted(@NonNull INode child, @NonNull INode parent, + @NonNull InsertType insertType) { // Overridden to inhibit the setting of layout_width/layout_height since // it should always be match_parent } @@ -69,13 +72,17 @@ public class TableLayoutRule extends LinearLayoutRule { * Add an explicit "Add Row" action to the context menu */ @Override - public void addContextMenuActions(List<RuleAction> actions, final INode selectedNode) { + public void addContextMenuActions(@NonNull List<RuleAction> actions, + final @NonNull INode selectedNode) { super.addContextMenuActions(actions, selectedNode); IMenuCallback addTab = new IMenuCallback() { @Override - public void action(RuleAction action, List<? extends INode> selectedNodes, - final String valueId, Boolean newValue) { + public void action( + @NonNull RuleAction action, + @NonNull List<? extends INode> selectedNodes, + final @Nullable String valueId, + @Nullable Boolean newValue) { final INode node = selectedNode; INode newRow = node.appendChild(FQCN_TABLE_ROW); mRulesEngine.select(Collections.singletonList(newRow)); @@ -85,8 +92,10 @@ public class TableLayoutRule extends LinearLayoutRule { } @Override - public void addLayoutActions(List<RuleAction> actions, final INode parentNode, - final List<? extends INode> children) { + public void addLayoutActions( + @NonNull List<RuleAction> actions, + final @NonNull INode parentNode, + final @NonNull List<? extends INode> children) { super.addLayoutActions(actions, parentNode, children); addTableLayoutActions(mRulesEngine, actions, parentNode, children); } @@ -99,11 +108,14 @@ public class TableLayoutRule extends LinearLayoutRule { final List<? extends INode> children) { IMenuCallback actionCallback = new IMenuCallback() { @Override - public void action(final RuleAction action, List<? extends INode> selectedNodes, - final String valueId, final Boolean newValue) { + public void action( + final @NonNull RuleAction action, + @NonNull List<? extends INode> selectedNodes, + final @Nullable String valueId, + final @Nullable Boolean newValue) { parentNode.editXml("Add/Remove Table Row", new INodeHandler() { @Override - public void handle(INode n) { + public void handle(@NonNull INode n) { if (action.getId().equals(ACTION_ADD_ROW)) { // Determine the index of the selection, if any; if there is // a selection, insert the row before the current row, otherwise @@ -171,7 +183,8 @@ public class TableLayoutRule extends LinearLayoutRule { } @Override - public void onCreate(INode node, INode parent, InsertType insertType) { + public void onCreate(@NonNull INode node, @NonNull INode parent, + @NonNull InsertType insertType) { super.onCreate(node, parent, insertType); if (insertType.isCreate()) { @@ -183,8 +196,9 @@ public class TableLayoutRule extends LinearLayoutRule { } @Override - public DropFeedback onResizeBegin(INode child, INode parent, SegmentType horizontalEdge, - SegmentType verticalEdge, Object childView, Object parentView) { + public DropFeedback onResizeBegin(@NonNull INode child, @NonNull INode parent, + @Nullable SegmentType horizontalEdge, @Nullable SegmentType verticalEdge, + @Nullable Object childView, @Nullable Object parentView) { // Children of a table layout cannot set their widths (it is controlled by column // settings on the table). They can set their heights (though for TableRow, the // height is always wrap_content). diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/TableRowRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/TableRowRule.java index f372866..af6f7a0 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/TableRowRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/TableRowRule.java @@ -17,6 +17,8 @@ package com.android.ide.common.layout; import static com.android.ide.common.layout.LayoutConstants.FQCN_TABLE_LAYOUT; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.ide.common.api.DropFeedback; import com.android.ide.common.api.INode; import com.android.ide.common.api.IViewRule; @@ -41,15 +43,18 @@ public class TableRowRule extends LinearLayoutRule { } @Override - public void onChildInserted(INode child, INode parent, InsertType insertType) { + public void onChildInserted(@NonNull INode child, @NonNull INode parent, + @NonNull InsertType insertType) { // Overridden to inhibit the setting of layout_width/layout_height since // the table row will enforce match_parent and wrap_content for width and height // respectively. } @Override - public void addLayoutActions(List<RuleAction> actions, final INode parentNode, - final List<? extends INode> children) { + public void addLayoutActions( + @NonNull List<RuleAction> actions, + final @NonNull INode parentNode, + final @NonNull List<? extends INode> children) { super.addLayoutActions(actions, parentNode, children); // Also apply table-specific actions on the table row such that you can @@ -65,8 +70,9 @@ public class TableRowRule extends LinearLayoutRule { } @Override - public DropFeedback onResizeBegin(INode child, INode parent, SegmentType horizontalEdge, - SegmentType verticalEdge, Object childView, Object parentView) { + public DropFeedback onResizeBegin(@NonNull INode child, @NonNull INode parent, + @Nullable SegmentType horizontalEdge, @Nullable SegmentType verticalEdge, + @Nullable Object childView, @Nullable Object parentView) { // No resizing in TableRows; the width is *always* match_parent and the height is // *always* wrap_content. return null; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/WebViewRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/WebViewRule.java index 5224df0..b2c8413 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/WebViewRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/WebViewRule.java @@ -16,10 +16,11 @@ package com.android.ide.common.layout; -import static com.android.util.XmlUtils.ANDROID_URI; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_HEIGHT; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_WIDTH; +import static com.android.util.XmlUtils.ANDROID_URI; +import com.android.annotations.NonNull; import com.android.ide.common.api.INode; import com.android.ide.common.api.IViewRule; import com.android.ide.common.api.InsertType; @@ -32,7 +33,8 @@ public class WebViewRule extends IgnoredLayoutRule { // into; it's an AbsoluteLayout for implementation purposes. @Override - public void onCreate(INode node, INode parent, InsertType insertType) { + public void onCreate(@NonNull INode node, @NonNull INode parent, + @NonNull InsertType insertType) { super.onCreate(node, parent, insertType); if (insertType.isCreate()) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ZoomButtonRule.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ZoomButtonRule.java index 5714392..3456fb9 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ZoomButtonRule.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/ZoomButtonRule.java @@ -15,15 +15,17 @@ */ package com.android.ide.common.layout; -import static com.android.util.XmlUtils.ANDROID_URI; import static com.android.ide.common.layout.LayoutConstants.ATTR_SRC; +import static com.android.util.XmlUtils.ANDROID_URI; +import com.android.annotations.NonNull; import com.android.ide.common.api.INode; import com.android.ide.common.api.InsertType; public class ZoomButtonRule extends BaseViewRule { @Override - public void onCreate(INode node, INode parent, InsertType insertType) { + public void onCreate(@NonNull INode node, @NonNull INode parent, + @NonNull InsertType insertType) { super.onCreate(node, parent, insertType); if (insertType.isCreate()) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/grid/GridLayoutPainter.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/grid/GridLayoutPainter.java index 3a73558..461ca2b 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/grid/GridLayoutPainter.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/grid/GridLayoutPainter.java @@ -19,6 +19,7 @@ import static com.android.ide.common.layout.GridLayoutRule.GRID_SIZE; import static com.android.ide.common.layout.GridLayoutRule.MARGIN_SIZE; import static com.android.ide.common.layout.grid.GridModel.UNDEFINED; +import com.android.annotations.NonNull; import com.android.ide.common.api.DrawingStyle; import com.android.ide.common.api.DropFeedback; import com.android.ide.common.api.IDragElement; @@ -127,7 +128,8 @@ public class GridLayoutPainter { // Implements IFeedbackPainter @Override - public void paint(IGraphics gc, INode node, DropFeedback feedback) { + public void paint(@NonNull IGraphics gc, @NonNull INode node, + @NonNull DropFeedback feedback) { Rect b = node.getBounds(); if (!b.isValid()) { return; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/GuidelinePainter.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/GuidelinePainter.java index b37a6ed..46038ee 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/GuidelinePainter.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/layout/relative/GuidelinePainter.java @@ -23,6 +23,7 @@ import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_PREFIX; import static com.android.ide.common.layout.LayoutConstants.ID_PREFIX; import static com.android.ide.common.layout.LayoutConstants.NEW_ID_PREFIX; +import com.android.annotations.NonNull; import com.android.ide.common.api.DrawingStyle; import com.android.ide.common.api.DropFeedback; import com.android.ide.common.api.IFeedbackPainter; @@ -45,7 +46,7 @@ import java.util.Set; public final class GuidelinePainter implements IFeedbackPainter { // ---- Implements IFeedbackPainter ---- @Override - public void paint(IGraphics gc, INode node, DropFeedback feedback) { + public void paint(@NonNull IGraphics gc, @NonNull INode node, @NonNull DropFeedback feedback) { GuidelineHandler state = (GuidelineHandler) feedback.userData; for (INode dragged : state.mDraggedNodes) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/resources/platform/AttributeInfo.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/resources/platform/AttributeInfo.java index 7b3e8a3..05f0adf 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/resources/platform/AttributeInfo.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/common/resources/platform/AttributeInfo.java @@ -86,13 +86,13 @@ public class AttributeInfo implements IAttributeInfo { /** Returns the XML Name of the attribute */ @Override - public String getName() { + public @NonNull String getName() { return mName; } /** Returns the formats of the attribute. Cannot be null. * Should have at least one format. */ @Override - public EnumSet<Format> getFormats() { + public @NonNull EnumSet<Format> getFormats() { return mFormats; } /** Returns the values for enums. null for other types. */ @@ -107,7 +107,7 @@ public class AttributeInfo implements IAttributeInfo { } /** Returns a short javadoc, .i.e. the first sentence. */ @Override - public String getJavaDoc() { + public @NonNull String getJavaDoc() { return mJavaDoc; } /** Returns the documentation for deprecated attributes. Null if not deprecated. */ @@ -157,7 +157,7 @@ public class AttributeInfo implements IAttributeInfo { * this attribute */ @Override - public String getDefinedBy() { + public @NonNull String getDefinedBy() { return mDefinedBy; } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java index cb5faba..9c1040e 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtConstants.java @@ -142,6 +142,9 @@ public class AdtConstants { /** Temporary packaged resources file name, i.e. "resources.ap_" */ public final static String FN_RESOURCES_AP_ = "resources.ap_"; //$NON-NLS-1$ + /** aapt's proguard output */ + public final static String FN_AAPT_PROGUARD = "proguard.txt"; //$NON-NLS-1$ + public final static String FN_TRACEVIEW = (SdkConstants.CURRENT_PLATFORM == SdkConstants.PLATFORM_WINDOWS) ? "traceview.bat" : "traceview"; //$NON-NLS-1$ //$NON-NLS-2$ diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java index 09092e7..47e650d 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtUtils.java @@ -444,6 +444,23 @@ public class AdtUtils { } /** + * Converts a workspace-relative path to an absolute file path + * + * @param path the workspace-relative path to convert + * @return the corresponding absolute file in the file system + */ + @NonNull + public static File workspacePathToFile(@NonNull IPath path) { + IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); + IResource res = root.findMember(path); + if (res != null) { + return res.getLocation().toFile(); + } + + return path.toFile(); + } + + /** * Converts a {@link File} to an {@link IFile}, if possible. * * @param file a file to be converted diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/VersionCheck.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/VersionCheck.java index 594912b..b002ff5 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/VersionCheck.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/VersionCheck.java @@ -74,12 +74,11 @@ public final class VersionCheck { int minMajorVersion = -1; int minMinorVersion = -1; int minMicroVersion = -1; - FileReader reader = null; + BufferedReader reader = null; try { - reader = new FileReader(osLibs + SdkConstants.FN_PLUGIN_PROP); - BufferedReader bReader = new BufferedReader(reader); + reader = new BufferedReader(new FileReader(osLibs + SdkConstants.FN_PLUGIN_PROP)); String line; - while ((line = bReader.readLine()) != null) { + while ((line = reader.readLine()) != null) { Matcher m = sPluginVersionPattern.matcher(line); if (m.matches()) { minMajorVersion = Integer.parseInt(m.group(1)); @@ -139,10 +138,9 @@ public final class VersionCheck { String osTools = osSdkPath + SdkConstants.OS_SDK_TOOLS_FOLDER; FullRevision toolsRevision = new FullRevision(Integer.MAX_VALUE); try { - reader = new FileReader(osTools + SdkConstants.FN_SOURCE_PROP); - BufferedReader bReader = new BufferedReader(reader); + reader = new BufferedReader(new FileReader(osTools + SdkConstants.FN_SOURCE_PROP)); String line; - while ((line = bReader.readLine()) != null) { + while ((line = reader.readLine()) != null) { Matcher m = sSourcePropPattern.matcher(line); if (m.matches()) { try { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/DexDumpAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/DexDumpAction.java index 7345a04..5fe47d9 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/DexDumpAction.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/DexDumpAction.java @@ -16,6 +16,7 @@ package com.android.ide.eclipse.adt.internal.actions; +import com.android.annotations.Nullable; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.AdtUtils; import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs.BuildVerbosity; @@ -164,40 +165,43 @@ public class DexDumpAction implements IObjectActionDelegate { final Process process = Runtime.getRuntime().exec(command); final BufferedWriter writer = new BufferedWriter(new FileWriter(dstFile)); - - final String lineSep = AdtUtils.getLineSeparator(); - - int err = GrabProcessOutput.grabProcessOutput( - process, - Wait.WAIT_FOR_READERS, - new IProcessOutput() { - @Override - public void out(String line) { - if (line != null) { - try { - writer.write(line); - writer.write(lineSep); - } catch (IOException ignore) {} + try { + final String lineSep = AdtUtils.getLineSeparator(); + + int err = GrabProcessOutput.grabProcessOutput( + process, + Wait.WAIT_FOR_READERS, + new IProcessOutput() { + @Override + public void out(@Nullable String line) { + if (line != null) { + try { + writer.write(line); + writer.write(lineSep); + } catch (IOException ignore) {} + } } - } - @Override - public void err(String line) { - if (line != null) { - AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, - project, line); + @Override + public void err(@Nullable String line) { + if (line != null) { + AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, + project, line); + } } - } - }); - - if (err == 0) { - // The command worked. In this case we don't remove the - // temp file in the finally block. - removeDstFile = false; - } else { - AdtPlugin.printErrorToConsole(project, - "DexDump failed with code " + Integer.toString(err)); //$NON-NLS-1$ - return Status.OK_STATUS; + }); + + if (err == 0) { + // The command worked. In this case we don't remove the + // temp file in the finally block. + removeDstFile = false; + } else { + AdtPlugin.printErrorToConsole(project, + "DexDump failed with code " + Integer.toString(err)); //$NON-NLS-1$ + return Status.OK_STATUS; + } + } finally { + writer.close(); } } catch (InterruptedException e) { // ? diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/SdkManagerAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/SdkManagerAction.java index 0ff50b5..ce9030e 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/SdkManagerAction.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/actions/SdkManagerAction.java @@ -16,6 +16,7 @@ package com.android.ide.eclipse.adt.internal.actions;
+import com.android.annotations.Nullable;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.internal.build.DexWrapper;
import com.android.ide.eclipse.adt.internal.sdk.AdtConsoleSdkLog;
@@ -98,12 +99,12 @@ public class SdkManagerAction implements IWorkbenchWindowActionDelegate, IObject Wait.ASYNC,
new IProcessOutput() {
@Override
- public void out(String line) {
+ public void out(@Nullable String line) {
// Ignore stdout
}
@Override
- public void err(String line) {
+ public void err(@Nullable String line) {
if (line != null) {
logger.printf("[SDK Manager] %s", line);
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java index 0f556f9..799cf0e 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/BuildHelper.java @@ -16,6 +16,7 @@ package com.android.ide.eclipse.adt.internal.build; +import com.android.annotations.Nullable; import com.android.ide.eclipse.adt.AdtConstants; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.AndroidPrintStream; @@ -1065,7 +1066,7 @@ public class BuildHelper { @SuppressWarnings("unused") @Override - public void out(String line) { + public void out(@Nullable String line) { if (line != null) { // If benchmarking always print the lines that // correspond to benchmarking info returned by ADT @@ -1080,7 +1081,7 @@ public class BuildHelper { } @Override - public void err(String line) { + public void err(@Nullable String line) { if (line != null) { results.add(line); if (BuildVerbosity.VERBOSE == AdtPrefs.getPrefs().getBuildVerbosity()) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java index 0347af6..8a9364e 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/builders/PreCompilerBuilder.java @@ -46,6 +46,7 @@ import com.android.sdklib.IAndroidTarget; import com.android.sdklib.ISdkLog; import com.android.sdklib.SdkConstants; import com.android.sdklib.internal.build.BuildConfigGenerator; +import com.android.sdklib.internal.project.ProjectProperties; import com.android.sdklib.io.FileOp; import com.android.sdklib.xml.AndroidManifest; import com.android.sdklib.xml.ManifestData; @@ -648,8 +649,14 @@ public class PreCompilerBuilder extends BaseBuilder { if (DEBUG_LOG) { AdtPlugin.log(IStatus.INFO, "%s compiling resources!", project.getName()); } + + IFile proguardFile = null; + if (projectState.getProperty(ProjectProperties.PROPERTY_PROGUARD_CONFIG) != null) { + proguardFile = androidOutputFolder.getFile(AdtConstants.FN_AAPT_PROGUARD); + } + handleResources(project, javaPackage, projectTarget, manifestFile, libProjects, - projectState.isLibrary()); + projectState.isLibrary(), proguardFile); } if (processorStatus == SourceProcessor.COMPILE_STATUS_NONE && @@ -882,7 +889,7 @@ public class PreCompilerBuilder extends BaseBuilder { * @throws AbortBuildException */ private void handleResources(IProject project, String javaPackage, IAndroidTarget projectTarget, - IFile manifest, List<IProject> libProjects, boolean isLibrary) + IFile manifest, List<IProject> libProjects, boolean isLibrary, IFile proguardFile) throws CoreException, AbortBuildException { // get the resource folder IFolder resFolder = project.getFolder(AdtConstants.WS_RESOURCES); @@ -941,8 +948,11 @@ public class PreCompilerBuilder extends BaseBuilder { } + String proguardFilePath = proguardFile != null ? + proguardFile.getLocation().toOSString(): null; + execAapt(project, projectTarget, osOutputPath, osResPath, osManifestPath, - mainPackageFolder, libResFolders, libPackages, isLibrary); + mainPackageFolder, libResFolders, libPackages, isLibrary, proguardFilePath); } } @@ -959,14 +969,16 @@ public class PreCompilerBuilder extends BaseBuilder { * If <var>customJavaPackage</var> is not null, this must match the new destination triggered * by its value. * @param libResFolders the list of res folders for the library. - * @param libraryPackages an optional list of javapackages to replace the main project java package. - * can be null. + * @param libraryPackages an optional list of javapackages to replace the main project java + * package. can be null. * @param isLibrary if the project is a library project + * @param proguardFile an optional path to store proguard information * @throws AbortBuildException */ private void execAapt(IProject project, IAndroidTarget projectTarget, String osOutputPath, String osResPath, String osManifestPath, IFolder packageFolder, - ArrayList<IFolder> libResFolders, String libraryPackages, boolean isLibrary) + ArrayList<IFolder> libResFolders, String libraryPackages, boolean isLibrary, + String proguardFile) throws AbortBuildException { // We actually need to delete the manifest.java as it may become empty and @@ -1016,6 +1028,12 @@ public class PreCompilerBuilder extends BaseBuilder { array.add("-I"); //$NON-NLS-1$ array.add(projectTarget.getPath(IAndroidTarget.ANDROID_JAR)); + // use the proguard file + if (proguardFile != null && proguardFile.length() > 0) { + array.add("-G"); + array.add(proguardFile); + } + if (AdtPrefs.getPrefs().getBuildVerbosity() == BuildVerbosity.VERBOSE) { StringBuilder sb = new StringBuilder(); for (String c : array) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/Hyperlinks.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/Hyperlinks.java index 6e035af..c63ed18 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/Hyperlinks.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/Hyperlinks.java @@ -16,14 +16,15 @@ package com.android.ide.eclipse.adt.internal.editors; -import static com.android.util.XmlUtils.ANDROID_URI; import static com.android.ide.common.layout.LayoutConstants.ATTR_CLASS; import static com.android.ide.common.layout.LayoutConstants.ATTR_NAME; import static com.android.ide.common.layout.LayoutConstants.ATTR_ON_CLICK; import static com.android.ide.common.layout.LayoutConstants.NEW_ID_PREFIX; import static com.android.ide.common.layout.LayoutConstants.VIEW; import static com.android.ide.common.resources.ResourceResolver.PREFIX_ANDROID_RESOURCE_REF; +import static com.android.ide.common.resources.ResourceResolver.PREFIX_ANDROID_THEME_REF; import static com.android.ide.common.resources.ResourceResolver.PREFIX_RESOURCE_REF; +import static com.android.ide.common.resources.ResourceResolver.PREFIX_THEME_REF; import static com.android.ide.eclipse.adt.AdtConstants.ANDROID_PKG; import static com.android.ide.eclipse.adt.AdtConstants.EXT_XML; import static com.android.ide.eclipse.adt.AdtConstants.FN_RESOURCE_BASE; @@ -38,6 +39,10 @@ import static com.android.sdklib.xml.AndroidManifest.ATTRIBUTE_NAME; import static com.android.sdklib.xml.AndroidManifest.ATTRIBUTE_PACKAGE; import static com.android.sdklib.xml.AndroidManifest.NODE_ACTIVITY; import static com.android.sdklib.xml.AndroidManifest.NODE_SERVICE; +import static com.android.tools.lint.detector.api.LintConstants.ANDROID_STYLE_RESOURCE_PREFIX; +import static com.android.tools.lint.detector.api.LintConstants.NEW_ID_RESOURCE_PREFIX; +import static com.android.tools.lint.detector.api.LintConstants.STYLE_RESOURCE_PREFIX; +import static com.android.util.XmlUtils.ANDROID_URI; import com.android.annotations.NonNull; import com.android.annotations.Nullable; @@ -210,14 +215,14 @@ public class Hyperlinks { } String value = attribute.getValue(); - if (value.startsWith("@+")) { //$NON-NLS-1$ + if (value.startsWith(NEW_ID_RESOURCE_PREFIX)) { // It's a value -declaration-, nowhere else to jump // (though we could consider jumping to the R-file; would that // be helpful?) return false; } - Pair<ResourceType,String> resource = ResourceHelper.parseResource(value); + Pair<ResourceType,String> resource = parseResource(value); if (resource != null) { ResourceType type = resource.getFirst(); if (type != null) { @@ -1026,23 +1031,28 @@ public class Hyperlinks { if (type == ResourceType.ID) { // Ids are recorded in <item> tags instead of <id> tags targetTag = "item"; //$NON-NLS-1$ - } else if (type == ResourceType.ATTR) { + } + + Pair<File, Integer> result = findTag(name, file, parser, document, targetTag); + if (result == null && type == ResourceType.ATTR) { // Attributes seem to be defined in <public> tags targetTag = "public"; //$NON-NLS-1$ + result = findTag(name, file, parser, document, targetTag); } - Element root = document.getDocumentElement(); - if (root.getTagName().equals(ROOT_ELEMENT)) { - NodeList children = root.getChildNodes(); - for (int i = 0, n = children.getLength(); i < n; i++) { - Node child = children.item(i); - if (child.getNodeType() == Node.ELEMENT_NODE) { - Element element = (Element) child; - if (element.getTagName().equals(targetTag)) { - String elementName = element.getAttribute(NAME_ATTR); - if (elementName.equals(name)) { + return result; + } - return Pair.of(file, parser.getOffset(element)); - } + private static Pair<File, Integer> findTag(String name, File file, OffsetTrackingParser parser, + Document document, String targetTag) { + NodeList children = document.getElementsByTagName(targetTag); + for (int i = 0, n = children.getLength(); i < n; i++) { + Node child = children.item(i); + if (child.getNodeType() == Node.ELEMENT_NODE) { + Element element = (Element) child; + if (element.getTagName().equals(targetTag)) { + String elementName = element.getAttribute(NAME_ATTR); + if (elementName.equals(name)) { + return Pair.of(file, parser.getOffset(element)); } } } @@ -1067,15 +1077,17 @@ public class Hyperlinks { } } - Pair<ResourceType,String> resource = ResourceHelper.parseResource(url); + Pair<ResourceType,String> resource = parseResource(url); if (resource == null) { - String androidStyle = "@android:style/"; //$NON-NLS-1$ + String androidStyle = ANDROID_STYLE_RESOURCE_PREFIX; if (url.startsWith(PREFIX_ANDROID_RESOURCE_REF)) { url = androidStyle + url.substring(PREFIX_ANDROID_RESOURCE_REF.length()); + } else if (url.startsWith(PREFIX_ANDROID_THEME_REF)) { + url = androidStyle + url.substring(PREFIX_ANDROID_THEME_REF.length()); } else if (url.startsWith(ANDROID_PKG + ':')) { url = androidStyle + url.substring(ANDROID_PKG.length() + 1); } else { - url = "@style/" + url; //$NON-NLS-1$ + url = STYLE_RESOURCE_PREFIX + url; } } return getResourceLinks(range, url); @@ -1087,6 +1099,16 @@ public class Hyperlinks { return getResourceLinks(range, url, project, configuration); } + /** Parse a resource reference or a theme reference and return the individual parts */ + private static Pair<ResourceType,String> parseResource(String url) { + if (url.startsWith(PREFIX_THEME_REF)) { + url = PREFIX_RESOURCE_REF + url.substring(PREFIX_THEME_REF.length()); + return ResourceHelper.parseResource(url); + } + + return ResourceHelper.parseResource(url); + } + /** * Computes hyperlinks to resource definitions for resource urls (e.g. * {@code @android:string/ok} or {@code @layout/foo}. May create multiple links. @@ -1101,14 +1123,15 @@ public class Hyperlinks { @NonNull IProject project, @Nullable FolderConfiguration configuration) { List<IHyperlink> links = new ArrayList<IHyperlink>(); - Pair<ResourceType,String> resource = ResourceHelper.parseResource(url); + Pair<ResourceType,String> resource = parseResource(url); if (resource == null || resource.getFirst() == null) { return null; } ResourceType type = resource.getFirst(); String name = resource.getSecond(); - boolean isFramework = url.startsWith("@android"); //$NON-NLS-1$ + boolean isFramework = url.startsWith(PREFIX_ANDROID_RESOURCE_REF) + || url.startsWith(PREFIX_ANDROID_THEME_REF); if (project == null) { // Local reference *within* a framework isFramework = true; @@ -1217,10 +1240,10 @@ public class Hyperlinks { return getStyleLinks(context, range, attribute.getValue()); } if (attribute != null - && attribute.getValue().startsWith(PREFIX_RESOURCE_REF)) { + && (attribute.getValue().startsWith(PREFIX_RESOURCE_REF) + || attribute.getValue().startsWith(PREFIX_THEME_REF))) { // Instantly create links for resources since we can use the existing // resolved maps for this and offer multiple choices for the user - String url = attribute.getValue(); return getResourceLinks(range, url); } @@ -1253,7 +1276,7 @@ public class Hyperlinks { int offset = caretOffset; while (offset > lineStart) { char c = document.getChar(offset); - if (c == '@') { + if (c == '@' || c == '?') { urlStart = offset; break; } else if (!isValidResourceUrlChar(c)) { diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimationEditorDelegate.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimationEditorDelegate.java index 153bc79..7c7051d 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimationEditorDelegate.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/animator/AnimationEditorDelegate.java @@ -18,6 +18,8 @@ package com.android.ide.eclipse.adt.internal.editors.animator; import static com.android.ide.eclipse.adt.AdtConstants.EDITORS_NAMESPACE; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.ide.eclipse.adt.AdtUtils; import com.android.ide.eclipse.adt.internal.editors.common.CommonXmlDelegate; import com.android.ide.eclipse.adt.internal.editors.common.CommonXmlEditor; @@ -41,8 +43,8 @@ public class AnimationEditorDelegate extends CommonXmlDelegate { @Override @SuppressWarnings("unchecked") public AnimationEditorDelegate createForFile( - CommonXmlEditor delegator, - ResourceFolderType type) { + @NonNull CommonXmlEditor delegator, + @Nullable ResourceFolderType type) { if (ResourceFolderType.ANIM == type || ResourceFolderType.ANIMATOR == type) { return new AnimationEditorDelegate(delegator); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/color/ColorEditorDelegate.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/color/ColorEditorDelegate.java index 53edea9..3389683 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/color/ColorEditorDelegate.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/color/ColorEditorDelegate.java @@ -18,6 +18,8 @@ package com.android.ide.eclipse.adt.internal.editors.color; import static com.android.ide.eclipse.adt.AdtConstants.EDITORS_NAMESPACE; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.ide.eclipse.adt.internal.editors.common.CommonXmlDelegate; import com.android.ide.eclipse.adt.internal.editors.common.CommonXmlEditor; import com.android.ide.eclipse.adt.internal.editors.descriptors.ElementDescriptor; @@ -39,8 +41,8 @@ public class ColorEditorDelegate extends CommonXmlDelegate { @Override @SuppressWarnings("unchecked") public ColorEditorDelegate createForFile( - CommonXmlEditor delegator, - ResourceFolderType type) { + @NonNull CommonXmlEditor delegator, + @Nullable ResourceFolderType type) { if (ResourceFolderType.COLOR == type) { return new ColorEditorDelegate(delegator); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/descriptors/ElementDescriptor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/descriptors/ElementDescriptor.java index 613a68f..7cfe791 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/descriptors/ElementDescriptor.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/descriptors/ElementDescriptor.java @@ -469,4 +469,17 @@ public class ElementDescriptor implements Comparable<ElementDescriptor> { public int compareTo(ElementDescriptor o) { return mUiName.compareToIgnoreCase(o.mUiName); } + + /** + * Ensures that this view descriptor's attribute list is up to date. This is + * always the case for all the builtin descriptors, but for example for a + * custom view, it could be changing dynamically so caches may have to be + * recomputed. This method will return true if nothing changed, and false if + * it recomputed its info. + * + * @return true if the attributes are already up to date and nothing changed + */ + public boolean syncAttributes() { + return true; + } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/drawable/DrawableEditorDelegate.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/drawable/DrawableEditorDelegate.java index 69d82bd..a54fa8c 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/drawable/DrawableEditorDelegate.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/drawable/DrawableEditorDelegate.java @@ -18,6 +18,8 @@ package com.android.ide.eclipse.adt.internal.editors.drawable; import static com.android.ide.eclipse.adt.AdtConstants.EDITORS_NAMESPACE; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.ide.eclipse.adt.internal.editors.common.CommonXmlDelegate; import com.android.ide.eclipse.adt.internal.editors.common.CommonXmlEditor; import com.android.ide.eclipse.adt.internal.editors.descriptors.DocumentDescriptor; @@ -40,8 +42,8 @@ public class DrawableEditorDelegate extends CommonXmlDelegate { @Override @SuppressWarnings("unchecked") public DrawableEditorDelegate createForFile( - CommonXmlEditor delegator, - ResourceFolderType type) { + @NonNull CommonXmlEditor delegator, + @Nullable ResourceFolderType type) { if (ResourceFolderType.DRAWABLE == type) { return new DrawableEditorDelegate(delegator); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/formatting/AndroidXmlFormattingStrategy.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/formatting/AndroidXmlFormattingStrategy.java index 23a5d35..41795d2 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/formatting/AndroidXmlFormattingStrategy.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/formatting/AndroidXmlFormattingStrategy.java @@ -270,7 +270,7 @@ public class AndroidXmlFormattingStrategy extends ContextBasedFormattingStrategy replaceEnd = document.getLength(); } else { root = DomUtilities.getCommonAncestor(startNode, endNode); - initialDepth = DomUtilities.getDepth(root) - 1; + initialDepth = root != null ? DomUtilities.getDepth(root) - 1 : 0; // Regions must be non-null since the DOM nodes are non null, but Eclipse null // analysis doesn't realize it: diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutEditorDelegate.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutEditorDelegate.java index 89dd263..8d7b02e 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutEditorDelegate.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutEditorDelegate.java @@ -100,8 +100,8 @@ public class LayoutEditorDelegate extends CommonXmlDelegate @Override @SuppressWarnings("unchecked") public LayoutEditorDelegate createForFile( - CommonXmlEditor delegator, - ResourceFolderType type) { + @NonNull CommonXmlEditor delegator, + @Nullable ResourceFolderType type) { if (ResourceFolderType.LAYOUT == type) { return new LayoutEditorDelegate(delegator); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutEditorMatchingStrategy.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutEditorMatchingStrategy.java index 6a6b99c..4ea49f9 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutEditorMatchingStrategy.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutEditorMatchingStrategy.java @@ -42,7 +42,8 @@ public class LayoutEditorMatchingStrategy implements IEditorMatchingStrategy { // get the IFile object and check it's in one of the layout folders. IFile iFile = fileInput.getFile(); - ResourceFolder resFolder = ResourceManager.getInstance().getResourceFolder(iFile); + ResourceManager manager = ResourceManager.getInstance(); + ResourceFolder resFolder = manager.getResourceFolder(iFile); // Per the IEditorMatchingStrategy documentation, editorRef.getEditorInput() // is expensive so try exclude files that definitely don't match, such @@ -61,6 +62,12 @@ public class LayoutEditorMatchingStrategy implements IEditorMatchingStrategy { FileEditorInput editorFileInput = (FileEditorInput)editorInput; IFile editorIFile = editorFileInput.getFile(); + ResourceFolder editorFolder = manager.getResourceFolder(editorIFile); + if (editorFolder == null + || editorFolder.getType() != ResourceFolderType.LAYOUT) { + return false; + } + return editorIFile.getProject().equals(iFile.getProject()) && editorIFile.getName().equals(iFile.getName()); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/CustomViewDescriptorService.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/CustomViewDescriptorService.java index a110c65..ab4e1e9 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/CustomViewDescriptorService.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/descriptors/CustomViewDescriptorService.java @@ -16,11 +16,11 @@ package com.android.ide.eclipse.adt.internal.editors.layout.descriptors; -import static com.android.util.XmlUtils.ANDROID_URI; import static com.android.sdklib.SdkConstants.CLASS_VIEWGROUP; import static com.android.tools.lint.detector.api.LintConstants.AUTO_URI; import static com.android.tools.lint.detector.api.LintConstants.URI_PREFIX; import static com.android.util.XmlUtils.ANDROID_NS_NAME_PREFIX; +import static com.android.util.XmlUtils.ANDROID_URI; import com.android.annotations.NonNull; import com.android.annotations.Nullable; @@ -44,12 +44,14 @@ import com.android.ide.eclipse.adt.internal.sdk.ProjectState; import com.android.ide.eclipse.adt.internal.sdk.Sdk; import com.android.resources.ResourceType; import com.android.sdklib.IAndroidTarget; +import com.google.common.collect.Maps; import com.google.common.collect.ObjectArrays; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.jdt.core.IClassFile; @@ -193,7 +195,8 @@ public final class CustomViewDescriptorService { // we have a valid parent, lets create a new ViewElementDescriptor. List<AttributeDescriptor> attrList = new ArrayList<AttributeDescriptor>(); List<AttributeDescriptor> paramList = new ArrayList<AttributeDescriptor>(); - findCustomDescriptors(project, type, attrList, paramList); + Map<ResourceFile, Long> files = findCustomDescriptors(project, type, + attrList, paramList); AttributeDescriptor[] attributes = getAttributeDescriptor(type, parentDescriptor); @@ -209,7 +212,8 @@ public final class CustomViewDescriptorService { ViewElementDescriptor descriptor = new CustomViewDescriptor(name, fqcn, attributes, layoutAttributes, - parentDescriptor.getChildren()); + parentDescriptor.getChildren(), + project, files); descriptor.setSuperClass(parentDescriptor); synchronized (mCustomDescriptorMap) { @@ -270,7 +274,7 @@ public final class CustomViewDescriptorService { } /** Compute/find the styleable resources for the given type, if possible */ - private void findCustomDescriptors( + private Map<ResourceFile, Long> findCustomDescriptors( IProject project, IType type, List<AttributeDescriptor> customAttributes, @@ -286,6 +290,8 @@ public final class CustomViewDescriptorService { Set<ResourceFile> resourceFiles = findAttrsFiles(library, className); if (resourceFiles != null && resourceFiles.size() > 0) { String appUri = getAppResUri(project); + Map<ResourceFile, Long> timestamps = + Maps.newHashMapWithExpectedSize(resourceFiles.size()); for (ResourceFile file : resourceFiles) { AttrsXmlParser attrsXmlParser = getParser(file); String fqcn = type.getFullyQualifiedName(); @@ -300,8 +306,14 @@ public final class CustomViewDescriptorService { classInfo, "Layout", null /*superClassInfo*/); //$NON-NLS-1$ attrsXmlParser.loadLayoutParamsAttributes(layoutInfo); appendAttributes(customLayoutAttributes, layoutInfo.getAttributes(), appUri); + + timestamps.put(file, file.getFile().getModificationStamp()); } + + return timestamps; } + + return null; } /** @@ -309,7 +321,7 @@ public final class CustomViewDescriptorService { * attributes for the given class name */ @Nullable - private Set<ResourceFile> findAttrsFiles(IProject library, String className) { + private static Set<ResourceFile> findAttrsFiles(IProject library, String className) { Set<ResourceFile> resourceFiles = null; ResourceManager manager = ResourceManager.getInstance(); ProjectResources resources = manager.getProjectResources(library); @@ -338,7 +350,7 @@ public final class CustomViewDescriptorService { * attrs.xml file in the same project. */ @Nullable - private IProject getProjectDeclaringType(IType type) { + private static IProject getProjectDeclaringType(IType type) { IClassFile classFile = type.getClassFile(); if (classFile != null) { IPath path = classFile.getPath(); @@ -358,7 +370,7 @@ public final class CustomViewDescriptorService { } /** Returns the name space to use for application attributes */ - private String getAppResUri(IProject project) { + private static String getAppResUri(IProject project) { String appResource; ProjectState projectState = Sdk.getProjectState(project); if (projectState != null && projectState.isLibrary()) { @@ -459,7 +471,7 @@ public final class CustomViewDescriptorService { ViewElementDescriptor descriptor = new CustomViewDescriptor(name, fqcn, getAttributeDescriptor(type, parentDescriptor), getLayoutAttributeDescriptors(type, parentDescriptor), - children); + children, project, null); descriptor.setSuperClass(parentDescriptor); // add it to the map @@ -504,10 +516,14 @@ public final class CustomViewDescriptorService { return parentDescriptor.getLayoutAttributes(); } - private static class CustomViewDescriptor extends ViewElementDescriptor { + private class CustomViewDescriptor extends ViewElementDescriptor { + private Map<ResourceFile, Long> mTimeStamps; + private IProject mProject; + public CustomViewDescriptor(String name, String fqcn, AttributeDescriptor[] attributes, AttributeDescriptor[] layoutAttributes, - ElementDescriptor[] children) { + ElementDescriptor[] children, IProject project, + Map<ResourceFile, Long> timestamps) { super( fqcn, // xml name name, // ui name @@ -519,6 +535,8 @@ public final class CustomViewDescriptorService { children, false // mandatory ); + mTimeStamps = timestamps; + mProject = project; } @Override @@ -533,5 +551,71 @@ public final class CustomViewDescriptorService { return iconFactory.getIcon("customView"); //$NON-NLS-1$ } + + @Override + public boolean syncAttributes() { + // Check if any of the descriptors + if (mTimeStamps != null) { + // Prevent checking actual file timestamps too frequently on rapid burst calls + long now = System.currentTimeMillis(); + if (now - sLastCheck < 1000) { + return true; + } + sLastCheck = now; + + // Check whether the resource files (typically just one) which defined + // custom attributes for this custom view have changed, and if so, + // refresh the attribute descriptors. + // This doesn't work the cases where you add descriptors for a custom + // view after using it, or add attributes in a separate file, but those + // scenarios aren't quite as common (and would require a bit more expensive + // analysis.) + for (Map.Entry<ResourceFile, Long> entry : mTimeStamps.entrySet()) { + ResourceFile file = entry.getKey(); + Long timestamp = entry.getValue(); + boolean recompute = false; + if (file.getFile().getModificationStamp() > timestamp.longValue()) { + // One or more attributes changed: recompute + recompute = true; + mParserCache.remove(file); + } + + if (recompute) { + IJavaProject javaProject = JavaCore.create(mProject); + String fqcn = getFullClassName(); + IType type = null; + try { + type = javaProject.findType(fqcn); + } catch (CoreException e) { + AdtPlugin.log(e, null); + } + if (type == null || !type.exists()) { + return true; + } + + List<AttributeDescriptor> attrList = new ArrayList<AttributeDescriptor>(); + List<AttributeDescriptor> paramList = new ArrayList<AttributeDescriptor>(); + + mTimeStamps = findCustomDescriptors(mProject, type, attrList, paramList); + + ViewElementDescriptor parentDescriptor = getSuperClassDesc(); + AttributeDescriptor[] attributes = + getAttributeDescriptor(type, parentDescriptor); + if (!attrList.isEmpty()) { + attributes = join(attrList, attributes); + } + attributes = attrList.toArray(new AttributeDescriptor[attrList.size()]); + setAttributes(attributes); + + return false; + } + } + } + + return true; + } } + + /** Timestamp of the most recent {@link CustomViewDescriptor#syncAttributes} check */ + private static long sLastCheck; } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CanvasTransform.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CanvasTransform.java index 7cbb8f2..e367f9e 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CanvasTransform.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/CanvasTransform.java @@ -104,7 +104,7 @@ public class CanvasTransform { * * @return The scaled image size in pixels. */ - public int getScalledImgSize() { + public int getScaledImgSize() { return (int) (mImgSize * mScale); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GCWrapper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GCWrapper.java index 664d473..354517e 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GCWrapper.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/GCWrapper.java @@ -16,6 +16,7 @@ package com.android.ide.eclipse.adt.internal.editors.layout.gle2; +import com.android.annotations.NonNull; import com.android.ide.common.api.DrawingStyle; import com.android.ide.common.api.IColor; import com.android.ide.common.api.IGraphics; @@ -135,7 +136,7 @@ public class GCWrapper implements IGraphics { //------------- @Override - public IColor registerColor(int rgb) { + public @NonNull IColor registerColor(int rgb) { checkGC(); Integer key = Integer.valueOf(rgb); @@ -163,13 +164,13 @@ public class GCWrapper implements IGraphics { } @Override - public IColor getForeground() { + public @NonNull IColor getForeground() { Color c = getGc().getForeground(); return new ColorWrapper(c); } @Override - public IColor getBackground() { + public @NonNull IColor getBackground() { Color c = getGc().getBackground(); return new ColorWrapper(c); } @@ -180,13 +181,13 @@ public class GCWrapper implements IGraphics { } @Override - public void setForeground(IColor color) { + public void setForeground(@NonNull IColor color) { checkGC(); getGc().setForeground(((ColorWrapper) color).getColor()); } @Override - public void setBackground(IColor color) { + public void setBackground(@NonNull IColor color) { checkGC(); getGc().setBackground(((ColorWrapper) color).getColor()); } @@ -203,7 +204,7 @@ public class GCWrapper implements IGraphics { } @Override - public void setLineStyle(LineStyle style) { + public void setLineStyle(@NonNull LineStyle style) { int swtStyle = 0; switch (style) { case LINE_SOLID: @@ -254,7 +255,7 @@ public class GCWrapper implements IGraphics { } @Override - public void drawLine(Point p1, Point p2) { + public void drawLine(@NonNull Point p1, @NonNull Point p2) { drawLine(p1.x, p1.y, p2.x, p2.y); } @@ -272,12 +273,12 @@ public class GCWrapper implements IGraphics { } @Override - public void drawRect(Point p1, Point p2) { + public void drawRect(@NonNull Point p1, @NonNull Point p2) { drawRect(p1.x, p1.y, p2.x, p2.y); } @Override - public void drawRect(Rect r) { + public void drawRect(@NonNull Rect r) { checkGC(); useStrokeAlpha(); int x = mHScale.translate(r.x); @@ -299,12 +300,12 @@ public class GCWrapper implements IGraphics { } @Override - public void fillRect(Point p1, Point p2) { + public void fillRect(@NonNull Point p1, @NonNull Point p2) { fillRect(p1.x, p1.y, p2.x, p2.y); } @Override - public void fillRect(Rect r) { + public void fillRect(@NonNull Rect r) { checkGC(); useFillAlpha(); int x = mHScale.translate(r.x); @@ -368,7 +369,7 @@ public class GCWrapper implements IGraphics { // strings @Override - public void drawString(String string, int x, int y) { + public void drawString(@NonNull String string, int x, int y) { checkGC(); useStrokeAlpha(); x = mHScale.translate(x); @@ -382,7 +383,7 @@ public class GCWrapper implements IGraphics { } @Override - public void drawBoxedStrings(int x, int y, List<?> strings) { + public void drawBoxedStrings(int x, int y, @NonNull List<?> strings) { checkGC(); x = mHScale.translate(x); @@ -414,14 +415,14 @@ public class GCWrapper implements IGraphics { } @Override - public void drawString(String string, Point topLeft) { + public void drawString(@NonNull String string, @NonNull Point topLeft) { drawString(string, topLeft.x, topLeft.y); } // Styles @Override - public void useStyle(DrawingStyle style) { + public void useStyle(@NonNull DrawingStyle style) { checkGC(); // Look up the specific SWT style which defines the actual diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageOverlay.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageOverlay.java index a5df4bd..d079ff4 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageOverlay.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/ImageOverlay.java @@ -32,6 +32,7 @@ import org.eclipse.swt.graphics.PaletteData; import java.awt.image.BufferedImage; import java.awt.image.DataBufferInt; import java.awt.image.WritableRaster; +import java.lang.ref.SoftReference; /** * The {@link ImageOverlay} class renders an image as an overlay. @@ -56,7 +57,17 @@ public class ImageOverlay extends Overlay implements IImageFactory { /** Current background AWT image. This is created by {@link #getImage()}, which is called * by the LayoutLib. */ - private BufferedImage mAwtImage; + private SoftReference<BufferedImage> mAwtImage = new SoftReference<BufferedImage>(null); + + /** + * Strong reference to the image in the above soft reference, to prevent + * garbage collection when {@link PRESCALE} is set, until the scaled image + * is created (lazily as part of the next paint call, where this strong + * reference is nulled out and the above soft reference becomes eligible to + * be reclaimed when memory is low.) + */ + @SuppressWarnings("unused") // Used by the garbage collector to keep mAwtImage non-soft + private BufferedImage mAwtImageStrongRef; /** The associated {@link LayoutCanvas}. */ private LayoutCanvas mCanvas; @@ -109,8 +120,10 @@ public class ImageOverlay extends Overlay implements IImageFactory { * @return The corresponding SWT image, or null. */ public synchronized Image setImage(BufferedImage awtImage, boolean isAlphaChannelImage) { - if (awtImage != mAwtImage || awtImage == null) { - mAwtImage = null; + BufferedImage oldAwtImage = mAwtImage.get(); + if (awtImage != oldAwtImage || awtImage == null) { + mAwtImage.clear(); + mAwtImageStrongRef = null; if (mImage != null) { mImage.dispose(); @@ -165,7 +178,12 @@ public class ImageOverlay extends Overlay implements IImageFactory { */ @Nullable BufferedImage getAwtImage() { - return mAwtImage; + BufferedImage awtImage = mAwtImage.get(); + if (awtImage == null && mImage != null) { + awtImage = SwtUtils.convertToAwt(mImage); + } + + return awtImage; } @Override @@ -184,11 +202,12 @@ public class ImageOverlay extends Overlay implements IImageFactory { // This is done lazily in paint rather than when the image changes because // the image must be rescaled each time the zoom level changes, which varies // independently from when the image changes. - if (PRESCALE && mAwtImage != null) { + BufferedImage awtImage = mAwtImage.get(); + if (PRESCALE && awtImage != null) { if (mPreScaledImage == null || - mPreScaledImage.getImageData().width != hi.getScalledImgSize()) { - double xScale = hi.getScalledImgSize() / (double) mAwtImage.getWidth(); - double yScale = vi.getScalledImgSize() / (double) mAwtImage.getHeight(); + mPreScaledImage.getImageData().width != hi.getScaledImgSize()) { + double xScale = hi.getScaledImgSize() / (double) awtImage.getWidth(); + double yScale = vi.getScaledImgSize() / (double) awtImage.getHeight(); BufferedImage scaledAwtImage; // NOTE: == comparison on floating point numbers is okay @@ -198,16 +217,18 @@ public class ImageOverlay extends Overlay implements IImageFactory { // of rounding errors. if (xScale == 1.0 && yScale == 1.0) { // Scaling to 100% is easy! - scaledAwtImage = mAwtImage; + scaledAwtImage = awtImage; } else { - scaledAwtImage = ImageUtils.scale(mAwtImage, xScale, yScale); + scaledAwtImage = ImageUtils.scale(awtImage, xScale, yScale); } - assert scaledAwtImage.getWidth() == hi.getScalledImgSize(); + assert scaledAwtImage.getWidth() == hi.getScaledImgSize(); if (mPreScaledImage != null && !mPreScaledImage.isDisposed()) { mPreScaledImage.dispose(); } mPreScaledImage = SwtUtils.convertToSwt(mCanvas.getDisplay(), scaledAwtImage, true /*transferAlpha*/, -1); + // We can't just clear the mAwtImageStrongRef here, because if the + // zooming factor changes, we may need to use it again } if (mPreScaledImage != null) { @@ -230,8 +251,8 @@ public class ImageOverlay extends Overlay implements IImageFactory { vi.getImgSize(), // srcHeight hi.translate(0), // destX vi.translate(0), // destY - hi.getScalledImgSize(), // destWidth - vi.getScalledImgSize()); // destHeight + hi.getScaledImgSize(), // destWidth + vi.getScaledImgSize()); // destHeight if (oldAlias != -2) { gc_setAntialias(gc, oldAlias); @@ -349,14 +370,19 @@ public class ImageOverlay extends Overlay implements IImageFactory { */ @Override public BufferedImage getImage(int w, int h) { - if (mAwtImage == null || - mAwtImage.getWidth() != w || - mAwtImage.getHeight() != h) { - - mAwtImage = SwtReadyBufferedImage.createImage(w, h, getDevice()); + BufferedImage awtImage = mAwtImage.get(); + if (awtImage == null || + awtImage.getWidth() != w || + awtImage.getHeight() != h) { + mAwtImage.clear(); + awtImage = SwtReadyBufferedImage.createImage(w, h, getDevice()); + mAwtImage = new SoftReference<BufferedImage>(awtImage); + if (PRESCALE) { + mAwtImageStrongRef = awtImage; + } } - return mAwtImage; + return awtImage; } /** diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlinePage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlinePage.java index 3524970..9261aff 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlinePage.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlinePage.java @@ -736,7 +736,8 @@ public class OutlinePage extends ContentOutlinePage // Temporary diagnostics code when developing GridLayout if (GridLayoutRule.sDebugGridLayout) { String namespace; - if (e.getParentNode().getNodeName().equals(GRID_LAYOUT)) { + if (e.getParentNode() != null + && e.getParentNode().getNodeName().equals(GRID_LAYOUT)) { namespace = ANDROID_URI; } else { IProject project = mGraphicalEditorPart.getProject(); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SimpleAttribute.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SimpleAttribute.java index b4a4772..198c164 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SimpleAttribute.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SimpleAttribute.java @@ -16,6 +16,7 @@ package com.android.ide.eclipse.adt.internal.editors.layout.gle2; +import com.android.annotations.NonNull; import com.android.ide.common.api.INode.IAttribute; import java.util.regex.Matcher; @@ -58,19 +59,19 @@ public class SimpleAttribute implements IAttribute { * Can be empty for an attribute without a namespace but is never null. */ @Override - public String getUri() { + public @NonNull String getUri() { return mUri; } /** Returns the XML local name of the attribute. Cannot be null nor empty. */ @Override - public String getName() { + public @NonNull String getName() { return mName; } /** Returns the value of the attribute. Cannot be null. Can be empty. */ @Override - public String getValue() { + public @NonNull String getValue() { return mValue; } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SimpleElement.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SimpleElement.java index e9abb06..4feff25 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SimpleElement.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/SimpleElement.java @@ -16,6 +16,8 @@ package com.android.ide.eclipse.adt.internal.editors.layout.gle2; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.ide.common.api.IDragElement; import com.android.ide.common.api.Rect; @@ -69,7 +71,7 @@ public class SimpleElement implements IDragElement { * a View to inflate. */ @Override - public String getFqcn() { + public @NonNull String getFqcn() { return mFqcn; } @@ -79,7 +81,7 @@ public class SimpleElement implements IDragElement { * from the object palette (unless it successfully rendered a preview) */ @Override - public Rect getBounds() { + public @NonNull Rect getBounds() { return mBounds; } @@ -98,12 +100,12 @@ public class SimpleElement implements IDragElement { * is no suitable parent. This is null when {@link #getParentFqcn()} is null. */ @Override - public Rect getParentBounds() { + public @NonNull Rect getParentBounds() { return mParentBounds; } @Override - public IDragAttribute[] getAttributes() { + public @NonNull IDragAttribute[] getAttributes() { if (mCachedAttributes == null) { mCachedAttributes = mAttributes.toArray(new IDragAttribute[mAttributes.size()]); } @@ -111,7 +113,7 @@ public class SimpleElement implements IDragElement { } @Override - public IDragAttribute getAttribute(String uri, String localName) { + public IDragAttribute getAttribute(@Nullable String uri, @NonNull String localName) { for (IDragAttribute attr : mAttributes) { if (attr.getUri().equals(uri) && attr.getName().equals(localName)) { return attr; @@ -122,7 +124,7 @@ public class SimpleElement implements IDragElement { } @Override - public IDragElement[] getInnerElements() { + public @NonNull IDragElement[] getInnerElements() { if (mCachedElements == null) { mCachedElements = mElements.toArray(new IDragElement[mElements.size()]); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ClientRulesEngine.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ClientRulesEngine.java index e08bfc1..e793983 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ClientRulesEngine.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/ClientRulesEngine.java @@ -21,6 +21,8 @@ import static com.android.sdklib.SdkConstants.CLASS_V4_FRAGMENT; import static com.android.tools.lint.detector.api.LintConstants.AUTO_URI; import static com.android.tools.lint.detector.api.LintConstants.URI_PREFIX; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.ide.common.api.IClientRulesEngine; import com.android.ide.common.api.INode; import com.android.ide.common.api.IValidator; @@ -110,12 +112,12 @@ class ClientRulesEngine implements IClientRulesEngine { } @Override - public String getFqcn() { + public @NonNull String getFqcn() { return mFqcn; } @Override - public void debugPrintf(String msg, Object... params) { + public void debugPrintf(@NonNull String msg, Object... params) { AdtPlugin.printToConsole( mFqcn == null ? "<unknown>" : mFqcn, String.format(msg, params) @@ -123,12 +125,12 @@ class ClientRulesEngine implements IClientRulesEngine { } @Override - public IViewRule loadRule(String fqcn) { + public IViewRule loadRule(@NonNull String fqcn) { return mRulesEngine.loadRule(fqcn, fqcn); } @Override - public void displayAlert(String message) { + public void displayAlert(@NonNull String message) { MessageDialog.openInformation( AdtPlugin.getDisplay().getActiveShell(), mFqcn, // title @@ -136,7 +138,8 @@ class ClientRulesEngine implements IClientRulesEngine { } @Override - public String displayInput(String message, String value, final IValidator filter) { + public String displayInput(@NonNull String message, @Nullable String value, + final @Nullable IValidator filter) { IInputValidator validator = null; if (filter != null) { validator = new IInputValidator() { @@ -166,26 +169,26 @@ class ClientRulesEngine implements IClientRulesEngine { } @Override - public IViewMetadata getMetadata(final String fqcn) { + public @NonNull IViewMetadata getMetadata(final @NonNull String fqcn) { return new IViewMetadata() { @Override - public String getDisplayName() { + public @NonNull String getDisplayName() { // This also works when there is no "." return fqcn.substring(fqcn.lastIndexOf('.') + 1); } @Override - public FillPreference getFillPreference() { + public @NonNull FillPreference getFillPreference() { return ViewMetadataRepository.get().getFillPreference(fqcn); } @Override - public Margins getInsets() { + public @NonNull Margins getInsets() { return mRulesEngine.getEditor().getCanvasControl().getInsets(fqcn); } @Override - public List<String> getTopAttributes() { + public @NonNull List<String> getTopAttributes() { return ViewMetadataRepository.get().getTopAttributes(fqcn); } }; @@ -205,10 +208,9 @@ class ClientRulesEngine implements IClientRulesEngine { } @Override - public IValidator getResourceValidator() { - // When https://review.source.android.com/#change,20168 is integrated, - // change this to - //return ResourceNameValidator.create(false, mDelegate.getProject(), ResourceType.ID); + public @Nullable IValidator getResourceValidator() { + //return ResourceNameValidator.create(false, mRulesEngine.getEditor().getProject(), + // ResourceType.ID); return null; } @@ -242,7 +244,8 @@ class ClientRulesEngine implements IClientRulesEngine { } @Override - public String displayResourceInput(String resourceTypeName, String currentValue) { + public String displayResourceInput(@NonNull String resourceTypeName, + @Nullable String currentValue) { return displayResourceInput(resourceTypeName, currentValue, null); } @@ -254,8 +257,8 @@ class ClientRulesEngine implements IClientRulesEngine { } @Override - public String[] displayMarginInput(String all, String left, String right, String top, - String bottom) { + public String[] displayMarginInput(@Nullable String all, @Nullable String left, + @Nullable String right, @Nullable String top, @Nullable String bottom) { GraphicalEditorPart editor = mRulesEngine.getEditor(); IProject project = editor.getProject(); if (project != null) { @@ -282,7 +285,7 @@ class ClientRulesEngine implements IClientRulesEngine { } @Override - public void select(final Collection<INode> nodes) { + public void select(final @NonNull Collection<INode> nodes) { LayoutCanvas layoutCanvas = mRulesEngine.getEditor().getCanvasControl(); final SelectionManager selectionManager = layoutCanvas.getSelectionManager(); selectionManager.select(nodes); @@ -440,8 +443,8 @@ class ClientRulesEngine implements IClientRulesEngine { } @Override - public Map<INode, Rect> measureChildren(INode parent, - IClientRulesEngine.AttributeFilter filter) { + public Map<INode, Rect> measureChildren(@NonNull INode parent, + @Nullable IClientRulesEngine.AttributeFilter filter) { RenderService renderService = RenderService.create(mRulesEngine.getEditor()); Map<INode, Rect> map = renderService.measureChildren(parent, filter); if (map == null) { @@ -502,7 +505,7 @@ class ClientRulesEngine implements IClientRulesEngine { } @Override - public String getUniqueId(String fqcn) { + public @NonNull String getUniqueId(@NonNull String fqcn) { UiDocumentNode root = mRulesEngine.getEditor().getModel(); String prefix = fqcn.substring(fqcn.lastIndexOf('.') + 1); prefix = Character.toLowerCase(prefix.charAt(0)) + prefix.substring(1); @@ -510,7 +513,7 @@ class ClientRulesEngine implements IClientRulesEngine { } @Override - public String getAppNameSpace() { + public @NonNull String getAppNameSpace() { IProject project = mRulesEngine.getEditor().getProject(); ProjectState projectState = Sdk.getProjectState(project); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/NodeProxy.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/NodeProxy.java index ea464c1..3cd9729 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/NodeProxy.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gre/NodeProxy.java @@ -16,6 +16,8 @@ package com.android.ide.eclipse.adt.internal.editors.layout.gre; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.ide.common.api.IAttributeInfo; import com.android.ide.common.api.INode; import com.android.ide.common.api.INodeHandler; @@ -86,16 +88,19 @@ public class NodeProxy implements INode { } @Override - public Rect getBounds() { + public @NonNull Rect getBounds() { return mBounds; } @Override - public Margins getMargins() { + public @NonNull Margins getMargins() { ViewHierarchy viewHierarchy = mFactory.getCanvas().getViewHierarchy(); CanvasViewInfo view = viewHierarchy.findViewInfoFor(this); if (view != null) { - return view.getMargins(); + Margins margins = view.getMargins(); + if (margins != null) { + return margins; + } } return NO_MARGINS; @@ -133,14 +138,15 @@ public class NodeProxy implements INode { } @Override - public String getFqcn() { + public @NonNull String getFqcn() { if (mNode != null) { ElementDescriptor desc = mNode.getDescriptor(); if (desc instanceof ViewElementDescriptor) { return ((ViewElementDescriptor) desc).getFullClassName(); } } - return null; + + return ""; } @@ -189,7 +195,7 @@ public class NodeProxy implements INode { } @Override - public INode[] getChildren() { + public @NonNull INode[] getChildren() { if (mNode != null) { List<UiElementNode> uiChildren = mNode.getUiChildren(); List<INode> nodes = new ArrayList<INode>(uiChildren.size()); @@ -209,7 +215,7 @@ public class NodeProxy implements INode { // ---- XML Editing --- @Override - public void editXml(String undoName, final INodeHandler c) { + public void editXml(@NonNull String undoName, final @NonNull INodeHandler c) { final AndroidXmlEditor editor = mNode.getEditor(); if (editor != null) { @@ -238,17 +244,17 @@ public class NodeProxy implements INode { } @Override - public INode appendChild(String viewFqcn) { + public @NonNull INode appendChild(@NonNull String viewFqcn) { return insertOrAppend(viewFqcn, -1); } @Override - public INode insertChildAt(String viewFqcn, int index) { + public @NonNull INode insertChildAt(@NonNull String viewFqcn, int index) { return insertOrAppend(viewFqcn, index); } @Override - public void removeChild(INode node) { + public void removeChild(@NonNull INode node) { checkEditOK(); ((NodeProxy) node).mNode.deleteXmlNode(); @@ -320,7 +326,10 @@ public class NodeProxy implements INode { } @Override - public boolean setAttribute(String uri, String name, String value) { + public boolean setAttribute( + @Nullable String uri, + @NonNull String name, + @Nullable String value) { checkEditOK(); UiAttributeNode attr = mNode.setAttributeValue(name, uri, value, true /* override */); @@ -345,7 +354,7 @@ public class NodeProxy implements INode { } @Override - public String getStringAttr(String uri, String attrName) { + public String getStringAttr(@Nullable String uri, @NonNull String attrName) { UiElementNode uiNode = mNode; if (attrName == null) { @@ -378,7 +387,7 @@ public class NodeProxy implements INode { } @Override - public IAttributeInfo getAttributeInfo(String uri, String attrName) { + public IAttributeInfo getAttributeInfo(@Nullable String uri, @NonNull String attrName) { UiElementNode uiNode = mNode; if (attrName == null) { @@ -399,7 +408,7 @@ public class NodeProxy implements INode { } @Override - public IAttributeInfo[] getDeclaredAttributes() { + public @NonNull IAttributeInfo[] getDeclaredAttributes() { AttributeDescriptor[] descs = mNode.getAttributeDescriptors(); int n = descs.length; @@ -413,7 +422,7 @@ public class NodeProxy implements INode { } @Override - public List<String> getAttributeSources() { + public @NonNull List<String> getAttributeSources() { ElementDescriptor descriptor = mNode.getDescriptor(); if (descriptor instanceof ViewElementDescriptor) { return ((ViewElementDescriptor) descriptor).getAttributeSources(); @@ -423,7 +432,7 @@ public class NodeProxy implements INode { } @Override - public IAttribute[] getLiveAttributes() { + public @NonNull IAttribute[] getLiveAttributes() { UiElementNode uiNode = mNode; if (uiNode.getXmlNode() != null) { @@ -446,7 +455,8 @@ public class NodeProxy implements INode { } } } - return null; + + return new IAttribute[0]; } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/properties/XmlPropertyEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/properties/XmlPropertyEditor.java index 628cda6..a7a863c 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/properties/XmlPropertyEditor.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/properties/XmlPropertyEditor.java @@ -309,21 +309,26 @@ class XmlPropertyEditor extends AbstractTextPropertyEditor { ResourceType type = null; List<ResourceType> types = null; if (formats.contains(Format.FLAG)) { - FlagXmlPropertyDialog dialog = + String[] flagValues = attributeInfo.getFlagValues(); + if (flagValues != null) { + FlagXmlPropertyDialog dialog = new FlagXmlPropertyDialog(propertyTable.getShell(), "Select Flag Values", false /* radio */, - attributeInfo.getFlagValues(), xmlProperty); - - dialog.open(); - return; + flagValues, xmlProperty); + dialog.open(); + return; + } } else if (formats.contains(Format.ENUM)) { - FlagXmlPropertyDialog dialog = + String[] enumValues = attributeInfo.getEnumValues(); + if (enumValues != null) { + FlagXmlPropertyDialog dialog = new FlagXmlPropertyDialog(propertyTable.getShell(), "Select Enum Value", true /* radio */, - attributeInfo.getEnumValues(), xmlProperty); - dialog.open(); - return; + enumValues, xmlProperty); + dialog.open(); + return; + } } else { for (Format format : formats) { ResourceType t = format.getResourceType(); @@ -379,16 +384,18 @@ class XmlPropertyEditor extends AbstractTextPropertyEditor { } else if (type != null) { // Single resource type: use a resource chooser GraphicalEditorPart graphicalEditor = xmlProperty.getGraphicalEditor(); - String currentValue = (String) property.getValue(); - // TODO: Add validator factory? - String resource = ResourceChooser.chooseResource(graphicalEditor, - type, currentValue, null /* validator */); - // Returns null for cancel, "" for clear and otherwise a new value - if (resource != null) { - if (resource.length() > 0) { - property.setValue(resource); - } else { - property.setValue(null); + if (graphicalEditor != null) { + String currentValue = (String) property.getValue(); + // TODO: Add validator factory? + String resource = ResourceChooser.chooseResource(graphicalEditor, + type, currentValue, null /* validator */); + // Returns null for cancel, "" for clear and otherwise a new value + if (resource != null) { + if (resource.length() > 0) { + property.setValue(resource); + } else { + property.setValue(null); + } } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeLayoutRefactoring.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeLayoutRefactoring.java index abbfa11..99369ee 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeLayoutRefactoring.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeLayoutRefactoring.java @@ -39,6 +39,7 @@ import static com.android.ide.common.layout.LayoutConstants.VALUE_WRAP_CONTENT; import static com.android.ide.eclipse.adt.AdtConstants.EXT_XML; import static com.android.util.XmlUtils.ANDROID_NS_NAME_PREFIX; +import com.android.annotations.NonNull; import com.android.annotations.VisibleForTesting; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor; @@ -218,7 +219,7 @@ public class ChangeLayoutRefactoring extends VisualRefactoring { } @Override - protected List<Change> computeChanges(IProgressMonitor monitor) { + protected @NonNull List<Change> computeChanges(IProgressMonitor monitor) { String name = getViewClass(mTypeFqcn); IFile file = mDelegate.getEditor().getInputFile(); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeViewRefactoring.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeViewRefactoring.java index 967a880..9cf3a3f 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeViewRefactoring.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ChangeViewRefactoring.java @@ -21,6 +21,7 @@ import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_PREFIX; import static com.android.ide.common.layout.LayoutConstants.ATTR_TEXT; import static com.android.ide.eclipse.adt.AdtConstants.EXT_XML; +import com.android.annotations.NonNull; import com.android.annotations.VisibleForTesting; import com.android.ide.eclipse.adt.internal.editors.descriptors.AttributeDescriptor; import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate; @@ -150,7 +151,7 @@ public class ChangeViewRefactoring extends VisualRefactoring { } @Override - protected List<Change> computeChanges(IProgressMonitor monitor) { + protected @NonNull List<Change> computeChanges(IProgressMonitor monitor) { String name = getViewClass(mTypeFqcn); IFile file = mDelegate.getEditor().getInputFile(); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractIncludeRefactoring.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractIncludeRefactoring.java index eb89304..657c9ec 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractIncludeRefactoring.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractIncludeRefactoring.java @@ -34,6 +34,7 @@ import static com.android.util.XmlUtils.XMLNS; import static com.android.util.XmlUtils.XMLNS_COLON; import com.android.AndroidConstants; +import com.android.annotations.NonNull; import com.android.annotations.VisibleForTesting; import com.android.ide.eclipse.adt.AdtConstants; import com.android.ide.eclipse.adt.AdtPlugin; @@ -221,7 +222,7 @@ public class ExtractIncludeRefactoring extends VisualRefactoring { // ---- Actual implementation of Extract as Include modification computation ---- @Override - protected List<Change> computeChanges(IProgressMonitor monitor) { + protected @NonNull List<Change> computeChanges(IProgressMonitor monitor) { String extractedText = getExtractedText(); String namespaceDeclarations = computeNamespaceDeclarations(); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractStyleRefactoring.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractStyleRefactoring.java index c6e965d..1c7dd72 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractStyleRefactoring.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/ExtractStyleRefactoring.java @@ -36,6 +36,7 @@ import static com.android.util.XmlUtils.ANDROID_NS_NAME; import static com.android.util.XmlUtils.ANDROID_NS_NAME_PREFIX; import static com.android.util.XmlUtils.XMLNS_COLON; +import com.android.annotations.NonNull; import com.android.annotations.VisibleForTesting; import com.android.ide.common.rendering.api.ResourceValue; import com.android.ide.common.resources.ResourceResolver; @@ -322,7 +323,7 @@ public class ExtractStyleRefactoring extends VisualRefactoring { } @Override - protected List<Change> computeChanges(IProgressMonitor monitor) { + protected @NonNull List<Change> computeChanges(IProgressMonitor monitor) { List<Change> changes = new ArrayList<Change>(); if (mChosenAttributes.size() == 0) { return changes; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UnwrapRefactoring.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UnwrapRefactoring.java index 050a787..e333629 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UnwrapRefactoring.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UnwrapRefactoring.java @@ -20,6 +20,7 @@ import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_HEIGHT; import static com.android.ide.common.layout.LayoutConstants.ATTR_LAYOUT_WIDTH; import static com.android.ide.eclipse.adt.AdtConstants.EXT_XML; +import com.android.annotations.NonNull; import com.android.annotations.VisibleForTesting; import com.android.ide.eclipse.adt.internal.editors.formatting.XmlFormatStyle; import com.android.ide.eclipse.adt.internal.editors.layout.LayoutEditorDelegate; @@ -166,7 +167,7 @@ public class UnwrapRefactoring extends VisualRefactoring { } @Override - protected List<Change> computeChanges(IProgressMonitor monitor) { + protected @NonNull List<Change> computeChanges(IProgressMonitor monitor) { // (1) If the removed parent is the root container, transfer its // namespace declarations // (2) Remove the root element completely diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UseCompoundDrawableRefactoring.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UseCompoundDrawableRefactoring.java index 8f9beab..453daa8 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UseCompoundDrawableRefactoring.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/UseCompoundDrawableRefactoring.java @@ -33,6 +33,7 @@ import static com.android.ide.eclipse.adt.AdtConstants.EXT_XML; import static com.android.tools.lint.detector.api.LintConstants.IMAGE_VIEW; import static com.android.tools.lint.detector.api.LintConstants.TEXT_VIEW; +import com.android.annotations.NonNull; import com.android.annotations.VisibleForTesting; import com.android.ide.eclipse.adt.internal.editors.formatting.XmlFormatPreferences; import com.android.ide.eclipse.adt.internal.editors.formatting.XmlFormatStyle; @@ -189,7 +190,7 @@ public class UseCompoundDrawableRefactoring extends VisualRefactoring { } @Override - protected List<Change> computeChanges(IProgressMonitor monitor) { + protected @NonNull List<Change> computeChanges(IProgressMonitor monitor) { String androidNsPrefix = getAndroidNamespacePrefix(); IFile file = mDelegate.getEditor().getInputFile(); List<Change> changes = new ArrayList<Change>(); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/WrapInRefactoring.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/WrapInRefactoring.java index d043085..08a951b 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/WrapInRefactoring.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/WrapInRefactoring.java @@ -26,6 +26,7 @@ import static com.android.ide.common.layout.LayoutConstants.VALUE_WRAP_CONTENT; import static com.android.ide.eclipse.adt.AdtConstants.EXT_XML; import static com.android.util.XmlUtils.ANDROID_NS_NAME_PREFIX; +import com.android.annotations.NonNull; import com.android.annotations.VisibleForTesting; import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor; import com.android.ide.eclipse.adt.internal.editors.formatting.XmlFormatStyle; @@ -175,7 +176,7 @@ public class WrapInRefactoring extends VisualRefactoring { } @Override - protected List<Change> computeChanges(IProgressMonitor monitor) { + protected @NonNull List<Change> computeChanges(IProgressMonitor monitor) { // (1) Insert the new container in front of the beginning of the // first wrapped view // (2) If the container is the new root, transfer namespace declarations diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/uimodel/UiViewElementNode.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/uimodel/UiViewElementNode.java index ec19ea7..fef6022 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/uimodel/UiViewElementNode.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/uimodel/UiViewElementNode.java @@ -66,6 +66,9 @@ public class UiViewElementNode extends UiElementNode { */ @Override public AttributeDescriptor[] getAttributeDescriptors() { + if (!getDescriptor().syncAttributes()) { + mCachedAttributeDescriptors = null; + } if (mCachedAttributeDescriptors != null) { return mCachedAttributeDescriptors; } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestInfo.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestInfo.java index 2f10f68..8479b0d 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestInfo.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/ManifestInfo.java @@ -78,6 +78,7 @@ import org.xml.sax.InputSource; import org.xml.sax.SAXException; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.LinkedList; import java.util.List; @@ -488,7 +489,7 @@ public class ManifestInfo { try { IJavaProject javaProject = BaseProjectHelper.getJavaProject(project); if (javaProject == null) { - return null; + return Collections.emptyList(); } // TODO - look around a bit more and see if we can figure out whether the // call if from within a setContentView call! diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/menu/MenuEditorDelegate.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/menu/MenuEditorDelegate.java index faca295..b5056d9 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/menu/MenuEditorDelegate.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/menu/MenuEditorDelegate.java @@ -16,6 +16,8 @@ package com.android.ide.eclipse.adt.internal.editors.menu; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.ide.eclipse.adt.AdtConstants; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.internal.editors.common.CommonXmlDelegate; @@ -43,8 +45,8 @@ public class MenuEditorDelegate extends CommonXmlDelegate { @Override @SuppressWarnings("unchecked") public MenuEditorDelegate createForFile( - CommonXmlEditor delegator, - ResourceFolderType type) { + @NonNull CommonXmlEditor delegator, + @Nullable ResourceFolderType type) { if (ResourceFolderType.MENU == type) { return new MenuEditorDelegate(delegator); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/otherxml/OtherXmlEditorDelegate.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/otherxml/OtherXmlEditorDelegate.java index 138ff95..7d74516 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/otherxml/OtherXmlEditorDelegate.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/otherxml/OtherXmlEditorDelegate.java @@ -16,6 +16,8 @@ package com.android.ide.eclipse.adt.internal.editors.otherxml; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.ide.eclipse.adt.AdtConstants; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.internal.editors.common.CommonXmlDelegate; @@ -36,8 +38,8 @@ public class OtherXmlEditorDelegate extends CommonXmlDelegate { @Override @SuppressWarnings("unchecked") public OtherXmlEditorDelegate createForFile( - CommonXmlEditor delegator, - ResourceFolderType type) { + @NonNull CommonXmlEditor delegator, + @Nullable ResourceFolderType type) { if (ResourceFolderType.XML == type) { return new OtherXmlEditorDelegate(delegator); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/values/ValuesEditorDelegate.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/values/ValuesEditorDelegate.java index f253b30..94a6771 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/values/ValuesEditorDelegate.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/values/ValuesEditorDelegate.java @@ -16,6 +16,8 @@ package com.android.ide.eclipse.adt.internal.editors.values; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.ide.eclipse.adt.AdtConstants; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.internal.editors.common.CommonXmlDelegate; @@ -43,8 +45,8 @@ public class ValuesEditorDelegate extends CommonXmlDelegate { @Override @SuppressWarnings("unchecked") public ValuesEditorDelegate createForFile( - CommonXmlEditor delegator, - ResourceFolderType type) { + @NonNull CommonXmlEditor delegator, + @Nullable ResourceFolderType type) { if (ResourceFolderType.VALUES == type) { return new ValuesEditorDelegate(delegator); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/EclipseLintClient.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/EclipseLintClient.java index 703be80..e7c81c5 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/EclipseLintClient.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/EclipseLintClient.java @@ -15,8 +15,11 @@ */ package com.android.ide.eclipse.adt.internal.lint; +import static com.android.ide.eclipse.adt.AdtConstants.DOT_JAR; import static com.android.ide.eclipse.adt.AdtConstants.DOT_XML; import static com.android.ide.eclipse.adt.AdtConstants.MARKER_LINT; +import static com.android.ide.eclipse.adt.AdtUtils.workspacePathToFile; +import static com.android.sdklib.SdkConstants.FD_NATIVE_LIBS; import com.android.annotations.NonNull; import com.android.annotations.Nullable; @@ -45,6 +48,7 @@ import com.android.tools.lint.detector.api.Project; import com.android.tools.lint.detector.api.Severity; import com.android.tools.lint.detector.api.XmlContext; import com.android.util.Pair; +import com.google.common.collect.Maps; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; @@ -52,7 +56,9 @@ import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IStatus; +import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaProject; +import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.compiler.CategorizedProblem; import org.eclipse.jdt.internal.compiler.CompilationResult; import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies; @@ -85,6 +91,7 @@ import org.w3c.dom.Node; import java.io.File; import java.io.IOException; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -181,7 +188,8 @@ public class EclipseLintClient extends LintClient implements IDomParser { // ----- Extends LintClient ----- @Override - public void log(Severity severity, Throwable exception, String format, Object... args) { + public void log(@NonNull Severity severity, @Nullable Throwable exception, + @Nullable String format, @Nullable Object... args) { if (exception == null) { AdtPlugin.log(IStatus.WARNING, format, args); } else { @@ -206,7 +214,7 @@ public class EclipseLintClient extends LintClient implements IDomParser { // ----- Implements IDomParser ----- @Override - public Document parseXml(XmlContext context) { + public Document parseXml(@NonNull XmlContext context) { // Map File to IFile IFile file = AdtUtils.fileToIFile(context.file); if (file == null || !file.exists()) { @@ -233,25 +241,56 @@ public class EclipseLintClient extends LintClient implements IDomParser { return null; } + // Cache for {@link getProject} + private IProject mLastEclipseProject; + private Project mLastLintProject; + private IProject getProject(Project project) { + if (project == mLastLintProject) { + return mLastEclipseProject; + } + + mLastLintProject = project; + mLastEclipseProject = null; + if (mResources != null) { if (mResources.size() == 1) { - return mResources.get(0).getProject(); + IProject p = mResources.get(0).getProject(); + mLastEclipseProject = p; + return p; } + IProject last = null; for (IResource resource : mResources) { IProject p = resource.getProject(); - if (project.getDir().equals(AdtUtils.getAbsolutePath(p).toFile())) { - return p; + if (p != last) { + if (project.getDir().equals(AdtUtils.getAbsolutePath(p).toFile())) { + mLastEclipseProject = p; + return p; + } + last = p; } } } + return null; } @NonNull @Override - public Configuration getConfiguration(Project project) { + public Configuration getConfiguration(@NonNull Project project) { + return getConfigurationFor(project); + } + + /** + * Same as {@link #getConfiguration(Project)}, but {@code project} can be + * null in which case the global configuration is returned. + * + * @param project the project to look up + * @return a corresponding configuration + */ + @NonNull + public Configuration getConfigurationFor(@Nullable Project project) { if (project != null) { IProject eclipseProject = getProject(project); if (eclipseProject != null) { @@ -261,10 +300,10 @@ public class EclipseLintClient extends LintClient implements IDomParser { return GlobalLintConfiguration.get(); } - @Override - public void report(Context context, Issue issue, Severity s, Location location, - String message, Object data) { + public void report(@NonNull Context context, @NonNull Issue issue, @NonNull Severity s, + @Nullable Location location, + @NonNull String message, @Nullable Object data) { int severity = getMarkerSeverity(s); IMarker marker = null; if (location != null) { @@ -373,7 +412,8 @@ public class EclipseLintClient extends LintClient implements IDomParser { } } - LayoutEditorDelegate delegate = LayoutEditorDelegate.fromEditor(AdtUtils.getActiveEditor()); + IEditorPart activeEditor = AdtUtils.getActiveEditor(); + LayoutEditorDelegate delegate = LayoutEditorDelegate.fromEditor(activeEditor); if (delegate != null) { delegate.getGraphicalEditor().getLayoutActionBar().updateErrorIndicator(); } @@ -619,7 +659,7 @@ public class EclipseLintClient extends LintClient implements IDomParser { } @Override - public String readFile(File f) { + public @NonNull String readFile(@NonNull File f) { // Map File to IFile IFile file = AdtUtils.fileToIFile(f); if (file == null || !file.exists()) { @@ -658,17 +698,123 @@ public class EclipseLintClient extends LintClient implements IDomParser { } @Override - public Location getLocation(XmlContext context, Node node) { + public @NonNull Location getLocation(@NonNull XmlContext context, @NonNull Node node) { IStructuredModel model = (IStructuredModel) context.getProperty(MODEL_PROPERTY); return new LazyLocation(context.file, model.getStructuredDocument(), (IndexedRegion) node); } @Override - public Handle createLocationHandle(final XmlContext context, final Node node) { + public @NonNull Handle createLocationHandle(final @NonNull XmlContext context, + final @NonNull Node node) { IStructuredModel model = (IStructuredModel) context.getProperty(MODEL_PROPERTY); return new LazyLocation(context.file, model.getStructuredDocument(), (IndexedRegion) node); } + private Map<Project, ClassPathInfo> mProjectInfo; + + @Override + @NonNull + protected ClassPathInfo getClassPath(@NonNull Project project) { + ClassPathInfo info; + if (mProjectInfo == null) { + mProjectInfo = Maps.newHashMap(); + info = null; + } else { + info = mProjectInfo.get(project); + } + + if (info == null) { + List<File> sources = null; + List<File> classes = null; + List<File> libraries = null; + + IProject p = getProject(project); + if (p != null) { + try { + IJavaProject javaProject = BaseProjectHelper.getJavaProject(p); + + // Output path + File file = workspacePathToFile(javaProject.getOutputLocation()); + classes = Collections.singletonList(file); + + // Source path + IClasspathEntry[] entries = javaProject.getRawClasspath(); + sources = new ArrayList<File>(entries.length); + libraries = new ArrayList<File>(entries.length); + for (int i = 0; i < entries.length; i++) { + IClasspathEntry entry = entries[i]; + int kind = entry.getEntryKind(); + + if (kind == IClasspathEntry.CPE_VARIABLE) { + entry = JavaCore.getResolvedClasspathEntry(entry); + kind = entry.getEntryKind(); + } + + if (kind == IClasspathEntry.CPE_SOURCE) { + sources.add(workspacePathToFile(entry.getPath())); + } else if (kind == IClasspathEntry.CPE_LIBRARY) { + libraries.add(entry.getPath().toFile()); + } + // Note that we ignore IClasspathEntry.CPE_CONTAINER: + // Normal Android Eclipse projects supply both + // AdtConstants.CONTAINER_FRAMEWORK + // and + // AdtConstants.CONTAINER_LIBRARIES + // here. We ignore the framework classes for obvious reasons, + // but we also ignore the library container because lint will + // process the libraries differently. When Eclipse builds a + // project, it gets the .jar output of the library projects + // from this container, which means it doesn't have to process + // the library sources. Lint on the other hand wants to process + // the source code, so instead it actually looks at the + // project.properties file to find the libraries, and then it + // iterates over all the library projects in turn and analyzes + // those separately (but passing the main project for context, + // such that the including project's manifest declarations + // are used for data like minSdkVersion level). + // + // Note that this container will also contain *other* + // libraries (Java libraries, not library projects) that we + // *should* include. However, we can't distinguish these + // class path entries from the library project jars, + // so instead of looking at these, we simply listFiles() in + // the libs/ folder after processing the classpath info + } + + // Add in libraries + File libs = new File(project.getDir(), FD_NATIVE_LIBS); + if (libs.isDirectory()) { + File[] jars = libs.listFiles(); + if (jars != null) { + for (File jar : jars) { + if (AdtUtils.endsWith(jar.getPath(), DOT_JAR)) { + libraries.add(jar); + } + } + } + } + } catch (CoreException e) { + AdtPlugin.log(e, null); + } + } + + if (sources == null) { + sources = super.getClassPath(project).getSourceFolders(); + } + if (classes == null) { + classes = super.getClassPath(project).getClassFolders(); + } + if (libraries == null) { + libraries = super.getClassPath(project).getLibraries(); + } + + info = new ClassPathInfo(sources, classes, libraries); + mProjectInfo.put(project, info); + } + + return info; + } + /** * Returns the registry of issues to check from within Eclipse. * @@ -679,12 +825,13 @@ public class EclipseLintClient extends LintClient implements IDomParser { } @Override - public Class<? extends Detector> replaceDetector(Class<? extends Detector> detectorClass) { + public @NonNull Class<? extends Detector> replaceDetector( + @NonNull Class<? extends Detector> detectorClass) { return detectorClass; } @Override - public void dispose(XmlContext context, Document document) { + public void dispose(@NonNull XmlContext context, @NonNull Document document) { IStructuredModel model = (IStructuredModel) context.getProperty(MODEL_PROPERTY); assert model != null : context.file; if (model != null) { @@ -754,7 +901,7 @@ public class EclipseLintClient extends LintClient implements IDomParser { } @Override - public Location resolve() { + public @NonNull Location resolve() { return this; } } @@ -784,7 +931,7 @@ public class EclipseLintClient extends LintClient implements IDomParser { } @Override - public lombok.ast.Node parseJava(JavaContext context) { + public lombok.ast.Node parseJava(@NonNull JavaContext context) { if (USE_ECLIPSE_PARSER) { // Use Eclipse's compiler EcjTreeConverter converter = new EcjTreeConverter(); @@ -879,19 +1026,22 @@ public class EclipseLintClient extends LintClient implements IDomParser { } @Override - public Location getLocation(JavaContext context, lombok.ast.Node node) { + public @NonNull Location getLocation(@NonNull JavaContext context, + @NonNull lombok.ast.Node node) { lombok.ast.Position position = node.getPosition(); return Location.create(context.file, context.getContents(), position.getStart(), position.getEnd()); } @Override - public Handle createLocationHandle(JavaContext context, lombok.ast.Node node) { + public @NonNull Handle createLocationHandle(@NonNull JavaContext context, + @NonNull lombok.ast.Node node) { return new LocationHandle(context.file, node); } @Override - public void dispose(JavaContext context, lombok.ast.Node compilationUnit) { + public void dispose(@NonNull JavaContext context, + @NonNull lombok.ast.Node compilationUnit) { } /* Handle for creating positions cheaply and returning full fledged locations later */ @@ -906,7 +1056,7 @@ public class EclipseLintClient extends LintClient implements IDomParser { } @Override - public Location resolve() { + public @NonNull Location resolve() { lombok.ast.Position pos = mNode.getPosition(); return Location.create(mFile, null /*contents*/, pos.getStart(), pos.getEnd()); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/GlobalLintConfiguration.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/GlobalLintConfiguration.java index 646d752..5870501 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/GlobalLintConfiguration.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/GlobalLintConfiguration.java @@ -16,6 +16,7 @@ package com.android.ide.eclipse.adt.internal.lint; import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs; import com.android.tools.lint.client.api.Configuration; @@ -54,7 +55,7 @@ class GlobalLintConfiguration extends Configuration { } @Override - public Severity getSeverity(Issue issue) { + public Severity getSeverity(@NonNull Issue issue) { if (mSeverities == null) { IssueRegistry registry = EclipseLintClient.getRegistry(); mSeverities = new HashMap<Issue, Severity>(); @@ -94,14 +95,15 @@ class GlobalLintConfiguration extends Configuration { } @Override - public void ignore(Context context, Issue issue, Location location, String message, - Object data) { + public void ignore(@NonNull Context context, @NonNull Issue issue, + @Nullable Location location, @NonNull String message, + @Nullable Object data) { throw new UnsupportedOperationException( "Can't ignore() in global configurations"); //$NON-NLS-1$ } @Override - public void setSeverity(Issue issue, Severity severity) { + public void setSeverity(@NonNull Issue issue, @Nullable Severity severity) { if (mSeverities == null) { // Force initialization getSeverity(issue); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/LintColumn.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/LintColumn.java index 34af83b..297d94b 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/LintColumn.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/LintColumn.java @@ -146,7 +146,7 @@ abstract class LintColumn implements Comparator<IMarker> { } @Override - public String getColumnHeaderText() { + public @NonNull String getColumnHeaderText() { return "Description"; } @@ -156,12 +156,12 @@ abstract class LintColumn implements Comparator<IMarker> { } @Override - public String getValue(IMarker marker) { + public String getValue(@NonNull IMarker marker) { return getStyledValue(marker).toString(); } @Override - public StyledString getStyledValue(IMarker marker) { + public StyledString getStyledValue(@NonNull IMarker marker) { StyledString styledString = new StyledString(); String message = marker.getAttribute(IMarker.MESSAGE, ""); @@ -177,7 +177,7 @@ abstract class LintColumn implements Comparator<IMarker> { } @Override - public Image getImage(IMarker marker) { + public Image getImage(@NonNull IMarker marker) { int severity = marker.getAttribute(IMarker.SEVERITY, 0); ISharedImages sharedImages = PlatformUI.getWorkbench().getSharedImages(); switch (severity) { @@ -199,7 +199,7 @@ abstract class LintColumn implements Comparator<IMarker> { } @Override - public Font getFont(IMarker marker) { + public Font getFont(@NonNull IMarker marker) { int severity = marker.getAttribute(IMarker.SEVERITY, 0); if (severity == IMarker.SEVERITY_ERROR) { return JFaceResources.getFontRegistry().getBold( @@ -277,7 +277,7 @@ abstract class LintColumn implements Comparator<IMarker> { } @Override - public String getColumnHeaderText() { + public @NonNull String getColumnHeaderText() { return "Category"; } @@ -287,7 +287,7 @@ abstract class LintColumn implements Comparator<IMarker> { } @Override - public String getValue(IMarker marker) { + public String getValue(@NonNull IMarker marker) { Issue issue = mList.getIssue(marker); if (issue != null) { return issue.getCategory().getFullName(); @@ -303,7 +303,7 @@ abstract class LintColumn implements Comparator<IMarker> { } @Override - public String getColumnHeaderText() { + public @NonNull String getColumnHeaderText() { return "Location"; } @@ -313,12 +313,12 @@ abstract class LintColumn implements Comparator<IMarker> { } @Override - public String getValue(IMarker marker) { + public String getValue(@NonNull IMarker marker) { return getStyledValue(marker).toString(); } @Override - public StyledString getStyledValue(IMarker marker) { + public StyledString getStyledValue(@NonNull IMarker marker) { StyledString styledString = new StyledString(); // Combined location @@ -378,7 +378,7 @@ abstract class LintColumn implements Comparator<IMarker> { } @Override - public String getColumnHeaderText() { + public @NonNull String getColumnHeaderText() { return "File"; } @@ -393,7 +393,7 @@ abstract class LintColumn implements Comparator<IMarker> { } @Override - public String getValue(IMarker marker) { + public String getValue(@NonNull IMarker marker) { if (marker.getResource() instanceof IFile) { return marker.getResource().getName(); } else { @@ -408,7 +408,7 @@ abstract class LintColumn implements Comparator<IMarker> { } @Override - public String getColumnHeaderText() { + public @NonNull String getColumnHeaderText() { return "Path"; } @@ -423,7 +423,7 @@ abstract class LintColumn implements Comparator<IMarker> { } @Override - public String getValue(IMarker marker) { + public String getValue(@NonNull IMarker marker) { return marker.getResource().getFullPath().toOSString(); } } @@ -434,7 +434,7 @@ abstract class LintColumn implements Comparator<IMarker> { } @Override - public String getColumnHeaderText() { + public @NonNull String getColumnHeaderText() { return "Line"; } @@ -454,7 +454,7 @@ abstract class LintColumn implements Comparator<IMarker> { } @Override - public String getValue(IMarker marker) { + public String getValue(@NonNull IMarker marker) { int line = getLine(marker); if (line >= 1) { return Integer.toString(line); @@ -483,7 +483,7 @@ abstract class LintColumn implements Comparator<IMarker> { } @Override - public String getColumnHeaderText() { + public @NonNull String getColumnHeaderText() { return "Priority"; } @@ -503,7 +503,7 @@ abstract class LintColumn implements Comparator<IMarker> { } @Override - public String getValue(IMarker marker) { + public String getValue(@NonNull IMarker marker) { int priority = getPriority(marker); if (priority > 0) { return Integer.toString(priority); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/LintFixGenerator.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/LintFixGenerator.java index c81c0fc..32da203 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/LintFixGenerator.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/LintFixGenerator.java @@ -226,7 +226,7 @@ public class LintFixGenerator implements IMarkerResolutionGenerator2, IQuickAssi File dir = AdtUtils.getAbsolutePath(eclipseProject).toFile(); project = mClient.getProject(dir, dir); } - Configuration configuration = mClient.getConfiguration(project); + Configuration configuration = mClient.getConfigurationFor(project); if (thisFileOnly && configuration instanceof DefaultConfiguration) { File file = AdtUtils.getAbsolutePath(resource).toFile(); ((DefaultConfiguration) configuration).ignore(issue, file); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/ProjectLintConfiguration.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/ProjectLintConfiguration.java index 77cd115..9e4ca12 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/ProjectLintConfiguration.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/lint/ProjectLintConfiguration.java @@ -15,6 +15,7 @@ */ package com.android.ide.eclipse.adt.internal.lint; +import com.android.annotations.NonNull; import com.android.annotations.VisibleForTesting; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.AdtUtils; @@ -79,7 +80,7 @@ class ProjectLintConfiguration extends DefaultConfiguration { } @Override - public Severity getSeverity(Issue issue) { + public @NonNull Severity getSeverity(@NonNull Issue issue) { Severity severity = super.getSeverity(issue); if (mFatalOnly && severity != Severity.FATAL) { return Severity.IGNORE; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/LintPreferencePage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/LintPreferencePage.java index b2d7361..0bc2bfd 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/LintPreferencePage.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/preferences/LintPreferencePage.java @@ -165,7 +165,7 @@ public class LintPreferencePage extends PropertyPage implements IWorkbenchPrefer File dir = AdtUtils.getAbsolutePath(mProject).toFile(); project = mClient.getProject(dir, dir); } - mConfiguration = mClient.getConfiguration(project); + mConfiguration = mClient.getConfigurationFor(project); mSearch = new Text(container, SWT.SEARCH | SWT.ICON_CANCEL | SWT.ICON_SEARCH); mSearch.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 2, 1)); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java index 86c9b22..c391b1c 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ExportHelper.java @@ -37,6 +37,7 @@ import com.android.sdklib.internal.project.ProjectProperties; import com.android.sdklib.xml.AndroidManifest; import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IncrementalProjectBuilder; @@ -200,6 +201,13 @@ public final class ExportHelper { + " does not exist or is not a regular file", null)); } } + + // get the proguard file output by aapt + if (proguardConfigFiles != null) { + IFolder androidOutputFolder = BaseProjectHelper.getAndroidOutputFolder(project); + IFile proguardFile = androidOutputFolder.getFile(AdtConstants.FN_AAPT_PROGUARD); + proguardConfigFiles.add(proguardFile.getLocation().toFile()); + } } Collection<String> dxInput; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidJarLoader.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidJarLoader.java index 409210d..e2f8a57 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidJarLoader.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/sdk/AndroidJarLoader.java @@ -354,26 +354,29 @@ public class AndroidJarLoader extends ClassLoader implements IAndroidClassLoader // create streams to read the intermediary archive FileInputStream fis = new FileInputStream(mOsFrameworkLocation); ZipInputStream zis = new ZipInputStream(fis); + try { + // loop on the entries of the intermediary package and put them in the final package. + ZipEntry entry; - // loop on the entries of the intermediary package and put them in the final package. - ZipEntry entry; + while ((entry = zis.getNextEntry()) != null) { + // get the name of the entry. + String currEntryName = entry.getName(); - while ((entry = zis.getNextEntry()) != null) { - // get the name of the entry. - String currEntryName = entry.getName(); + if (currEntryName.equals(entryName)) { + long entrySize = entry.getSize(); + if (entrySize > Integer.MAX_VALUE) { + throw new InvalidAttributeValueException(); + } - if (currEntryName.equals(entryName)) { - long entrySize = entry.getSize(); - if (entrySize > Integer.MAX_VALUE) { - throw new InvalidAttributeValueException(); + data = readZipData(zis, (int)entrySize); + return data; } - - data = readZipData(zis, (int)entrySize); - return data; } - } - return null; + return null; + } finally { + zis.close(); + } } /** diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/ExportWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/ExportWizard.java index 8fcf902..d7ace9a 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/ExportWizard.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/ExportWizard.java @@ -16,6 +16,7 @@ package com.android.ide.eclipse.adt.internal.wizards.export; +import com.android.annotations.Nullable; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.internal.preferences.AdtPrefs.BuildVerbosity; import com.android.ide.eclipse.adt.internal.project.ExportHelper; @@ -547,7 +548,7 @@ public final class ExportWizard extends Wizard implements IExportWizard { Wait.WAIT_FOR_READERS, new IProcessOutput() { @Override - public void out(String line) { + public void out(@Nullable String line) { if (line != null) { AdtPlugin.printBuildToConsole(BuildVerbosity.VERBOSE, project, line); @@ -555,7 +556,7 @@ public final class ExportWizard extends Wizard implements IExportWizard { } @Override - public void err(String line) { + public void err(@Nullable String line) { if (line != null) { output.add(line); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/ActivityPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/ActivityPage.java index 22eb81a..9a61b4f 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/ActivityPage.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/ActivityPage.java @@ -16,9 +16,6 @@ package com.android.ide.eclipse.adt.internal.wizards.templates; import static com.android.ide.eclipse.adt.internal.wizards.templates.NewTemplateWizard.ACTIVITY_TEMPLATES; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_DESCRIPTION; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_NAME; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_THUMB; import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.PREVIEW_PADDING; import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.PREVIEW_WIDTH; @@ -41,8 +38,6 @@ import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.List; -import org.w3c.dom.Document; -import org.w3c.dom.Element; import java.io.InputStream; @@ -121,18 +116,17 @@ class ActivityPage extends WizardPage implements SelectionListener { setPreview(mValues.activityValues.getTemplateName()); } - private void setPreview(String template) { + private void setPreview(String templateName) { Image oldImage = mPreviewImage; mPreviewImage = null; String title = ""; String description = ""; - Document doc = TemplateHandler.getMetadataDocument(template); - if (doc != null) { - Element root = doc.getDocumentElement(); - String thumb = root.getAttribute(ATTR_THUMB); + TemplateMetadata template = TemplateHandler.getTemplate(templateName); + if (template != null) { + String thumb = template.getThumbnailPath(); if (thumb != null && !thumb.isEmpty()) { - String filePath = TemplateHandler.getTemplatePath(template) + '/' + thumb; + String filePath = TemplateHandler.getTemplatePath(templateName) + '/' + thumb; InputStream input = AdtPlugin.readEmbeddedFileAsStream(filePath); if (input != null) { try { @@ -143,8 +137,8 @@ class ActivityPage extends WizardPage implements SelectionListener { } } } - title = root.getAttribute(ATTR_NAME); - description = root.getAttribute(ATTR_DESCRIPTION); + title = template.getTitle(); + description = template.getDescription(); } mHeading.setText(title); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewProjectWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewProjectWizard.java index 9df974f..60f7a9e 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewProjectWizard.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewProjectWizard.java @@ -317,7 +317,7 @@ public class NewProjectWizard extends Wizard implements INewWizard { parameters.put(ATTR_TARGET_API, paramMap.get(ATTR_TARGET_API)); - TemplateHandler activityTemplate = activityValues.getTemplate(); + TemplateHandler activityTemplate = activityValues.getTemplateHandler(); activityTemplate.setBackupMergedFiles(false); activityTemplate.render(outputPath, parameters); List<String> filesToOpen = activityTemplate.getFilesToOpen(); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplatePage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplatePage.java index f89fd11..a6fdf48 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplatePage.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplatePage.java @@ -16,10 +16,8 @@ package com.android.ide.eclipse.adt.internal.wizards.templates; import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_DEFAULT; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_DESCRIPTION; import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_ID; import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_NAME; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_THUMB; import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.PREVIEW_PADDING; import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.PREVIEW_WIDTH; @@ -57,7 +55,6 @@ import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; -import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; @@ -160,16 +157,15 @@ public class NewTemplatePage extends WizardPage // Add parameters mFirst = null; - Document doc = mValues.getTemplate().getMetadataDocument(); + TemplateMetadata template = mValues.getTemplateHandler().getTemplate(); String thumb = null; - if (doc != null) { - Element root = doc.getDocumentElement(); - thumb = root.getAttribute(ATTR_THUMB); - String title = root.getAttribute(ATTR_NAME); + if (template != null) { + thumb = template.getThumbnailPath(); + String title = template.getTitle(); if (!title.isEmpty()) { setTitle(title); } - String description = root.getAttribute(ATTR_DESCRIPTION); + String description = template.getDescription(); if (!description.isEmpty()) { setDescription(description); } @@ -180,8 +176,7 @@ public class NewTemplatePage extends WizardPage seen = new HashSet<String>(); } - - List<Parameter> parameters = Parameter.getParameters(doc); + List<Parameter> parameters = template.getParameters(); mParameters = new ArrayList<Parameter>(parameters.size()); for (Parameter parameter : parameters) { Parameter.Type type = parameter.type; @@ -288,19 +283,14 @@ public class NewTemplatePage extends WizardPage int selected = 0; List<String> ids = Lists.newArrayList(); List<String> labels = Lists.newArrayList(); - List<String> thumbs = Lists.newArrayList(); for (int i = 0, n = options.size(); i < n; i++) { Element option = options.get(i); String optionId = option.getAttribute(ATTR_ID); assert optionId != null && !optionId.isEmpty() : ATTR_ID; - String optionThumb = option.getAttribute(ATTR_THUMB); String isDefault = option.getAttribute(ATTR_DEFAULT); if (isDefault != null && !isDefault.isEmpty() && Boolean.valueOf(isDefault)) { selected = i; - if (optionThumb != null && !optionThumb.isEmpty()) { - thumb = optionThumb; - } } NodeList childNodes = option.getChildNodes(); assert childNodes.getLength() == 1 && @@ -308,11 +298,9 @@ public class NewTemplatePage extends WizardPage String optionLabel = childNodes.item(0).getNodeValue().trim(); ids.add(optionId); labels.add(optionLabel); - thumbs.add(optionThumb); } combo.setData(parameter); parameter.control = combo; - combo.setData(ATTR_THUMB, thumbs.toArray(new String[thumbs.size()])); combo.setData(ATTR_ID, ids.toArray(new String[ids.size()])); assert labels.size() > 0; combo.setItems(labels.toArray(new String[labels.size()])); @@ -371,10 +359,14 @@ public class NewTemplatePage extends WizardPage } private void setPreview(String thumb) { + if (thumb == null) { + return; + } + Image oldImage = mPreviewImage; mPreviewImage = null; - byte[] data = mValues.getTemplate().readTemplateResource(thumb); + byte[] data = mValues.getTemplateHandler().readTemplateResource(thumb); if (data != null) { try { mPreviewImage = new Image(getControl().getDisplay(), @@ -546,15 +538,15 @@ public class NewTemplatePage extends WizardPage if (index != -1 && index < optionIds.length) { String optionId = optionIds[index]; editParameter(combo, optionId); - String[] thumbs = (String[]) combo.getData(ATTR_THUMB); - String thumb = thumbs[index]; - if (thumb != null && !thumb.isEmpty()) { - setPreview(thumb); - } + TemplateMetadata template = mValues.getTemplateHandler().getTemplate(); + setPreview(template.getThumbnailPath()); } } else if (source instanceof Button) { Button button = (Button) source; editParameter(button, button.getSelection()); + + TemplateMetadata template = mValues.getTemplateHandler().getTemplate(); + setPreview(template.getThumbnailPath()); } validatePage(); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplateWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplateWizard.java index 5fe91c5..b7ad998 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplateWizard.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplateWizard.java @@ -119,8 +119,8 @@ public class NewTemplateWizard extends Wizard implements INewWizard { parameters.put(ATTR_TARGET_API, manifest.getTargetSdkVersion()); File outputPath = AdtUtils.getAbsolutePath(project).toFile(); - TemplateHandler template = mValues.getTemplate(); - template.render(outputPath, parameters); + TemplateHandler handler = mValues.getTemplateHandler(); + handler.render(outputPath, parameters); try { project.refreshLocal(DEPTH_INFINITE, new NullProgressMonitor()); @@ -128,7 +128,7 @@ public class NewTemplateWizard extends Wizard implements INewWizard { AdtPlugin.log(e, null); } - List<String> filesToOpen = template.getFilesToOpen(); + List<String> filesToOpen = handler.getFilesToOpen(); NewTemplateWizard.openFiles(project, filesToOpen, mWorkbench); return true; diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplateWizardState.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplateWizardState.java index cb32a4f..dc75a71 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplateWizardState.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/NewTemplateWizardState.java @@ -37,7 +37,7 @@ public class NewTemplateWizardState { private String mTemplateName = BLANK_ACTIVITY; /** Template handler responsible for instantiating templates and reading resources */ - private TemplateHandler mTemplate; + private TemplateHandler mTemplateHandler; /** Configured parameters, by id */ public final Map<String, Object> parameters = new HashMap<String, Object>(); @@ -78,23 +78,23 @@ public class NewTemplateWizardState { if (!templateName.equals(mTemplateName)) { mTemplateName = templateName; mTemplateLocation = null; - mTemplate = null; + mTemplateHandler = null; } } @NonNull - TemplateHandler getTemplate() { - if (mTemplate == null) { + TemplateHandler getTemplateHandler() { + if (mTemplateHandler == null) { File inputPath; if (mTemplateLocation != null) { inputPath = mTemplateLocation; } else { inputPath = new File(TemplateHandler.getTemplatePath(mTemplateName)); } - mTemplate = TemplateHandler.createFromPath(inputPath); + mTemplateHandler = TemplateHandler.createFromPath(inputPath); } - return mTemplate; + return mTemplateHandler; } // For template development/testing only @@ -102,7 +102,7 @@ public class NewTemplateWizardState { if (!file.equals(mTemplateLocation)) { mTemplateLocation = file; mTemplateName = null; - mTemplate = null; + mTemplateHandler = null; } } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/Parameter.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/Parameter.java index 1fad0e1..0b8b952 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/Parameter.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/Parameter.java @@ -21,7 +21,6 @@ import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHan import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_ID; import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_NAME; import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_SUGGEST; -import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.TAG_PARAMETER; import com.android.annotations.NonNull; import com.android.annotations.Nullable; @@ -37,13 +36,9 @@ import org.eclipse.core.runtime.IStatus; import org.eclipse.jface.dialogs.IInputValidator; import org.eclipse.jface.fieldassist.ControlDecoration; import org.eclipse.swt.widgets.Control; -import org.w3c.dom.Document; import org.w3c.dom.Element; -import org.w3c.dom.NodeList; -import java.util.ArrayList; import java.util.EnumSet; -import java.util.List; import java.util.Locale; /** @@ -142,24 +137,7 @@ class Parameter { } } - /** The type of parameter. Must be one of - * <ul> - * <li> string - * <li> id - * <li> class - * <li> boolean - * <li> package - * <li> apiLevel - * <li> enum (must contain option children) - * <li> Resource types: - * <ul> - * <li> layout - * <li> <i>more to come</i> - * </ul> - * </ul> - * <p> - * TODO: Switch to an enum - */ + /** The type of parameter */ @NonNull public final Type type; @@ -346,16 +324,4 @@ class Parameter { return mValidator; } - - @NonNull - static List<Parameter> getParameters(@NonNull Document document) { - NodeList parameters = document.getElementsByTagName(TAG_PARAMETER); - List<Parameter> list = new ArrayList<Parameter>(parameters.getLength()); - for (int index = 0, max = parameters.getLength(); index < max; index++) { - Element element = (Element) parameters.item(index); - list.add(new Parameter(element)); - } - - return list; - } }
\ No newline at end of file diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateHandler.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateHandler.java index 8864502..4f107fb 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateHandler.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateHandler.java @@ -117,6 +117,8 @@ class TemplateHandler { static final String TAG_COPY = "copy"; //$NON-NLS-1$ static final String TAG_INSTANTIATE = "instantiate"; //$NON-NLS-1$ static final String TAG_OPEN = "open"; //$NON-NLS-1$ + static final String TAG_THUMB = "thumb"; //$NON-NLS-1$ + static final String TAG_THUMBS = "thumbs"; //$NON-NLS-1$ static final String ATTR_VALUE = "value"; //$NON-NLS-1$ static final String ATTR_DEFAULT = "default"; //$NON-NLS-1$ static final String ATTR_SUGGEST = "suggest"; //$NON-NLS-1$ @@ -129,7 +131,6 @@ class TemplateHandler { static final String ATTR_TO = "to"; //$NON-NLS-1$ static final String ATTR_FROM = "from"; //$NON-NLS-1$ static final String ATTR_CONSTRAINTS = "constraints";//$NON-NLS-1$ - static final String ATTR_THUMB = "thumb"; //$NON-NLS-1$ /** Default padding to apply in wizards around the thumbnail preview images */ static final int PREVIEW_PADDING = 10; @@ -161,6 +162,11 @@ class TemplateHandler { */ private boolean mBackupMergedFiles = true; + /** + * Template metadata + */ + private TemplateMetadata mTemplate; + /** Creates a new {@link TemplateHandler} for the given root path */ static TemplateHandler createFromPath(File rootPath) { return new TemplateHandler(rootPath); @@ -222,25 +228,38 @@ class TemplateHandler { } @Nullable - public Document getMetadataDocument() { - String xml = readTemplateTextResource(TEMPLATE_XML); - if (xml != null) { - return DomUtilities.parseDocument(xml, true); - } else { - return null; + public TemplateMetadata getTemplate() { + if (mTemplate == null) { + String xml = readTemplateTextResource(TEMPLATE_XML); + if (xml != null) { + Document doc = DomUtilities.parseDocument(xml, true); + if (doc != null && doc.getDocumentElement() != null) { + mTemplate = new TemplateMetadata(doc); + } + } } + + return mTemplate; } - public static Document getMetadataDocument(String templateName) { + @Nullable + public static TemplateMetadata getTemplate(String templateName) { String relative = getTemplatePath(templateName) + '/' +TEMPLATE_XML; String xml = AdtPlugin.readEmbeddedTextFile(relative); - return DomUtilities.parseDocument(xml, true); + Document doc = DomUtilities.parseDocument(xml, true); + if (doc != null && doc.getDocumentElement() != null) { + return new TemplateMetadata(doc); + } + + return null; } + @NonNull public static String getTemplatePath(String templateName) { return TEMPLATE_PREFIX + templateName; } + @NonNull public String getResourcePath(String templateName) { return new File(mRootPath.getPath(), templateName).getPath(); } @@ -513,6 +532,9 @@ class TemplateHandler { xml = out.toString(); } else { xml = readTemplateTextResource(from); + if (xml == null) { + return; + } } String currentXml = Files.toString(to, Charsets.UTF_8); diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateMetadata.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateMetadata.java new file mode 100644 index 0000000..eac818a --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/templates/TemplateMetadata.java @@ -0,0 +1,145 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php + * + * 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.ide.eclipse.adt.internal.wizards.templates; + +import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_DESCRIPTION; +import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.ATTR_NAME; +import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.TAG_PARAMETER; +import static com.android.ide.eclipse.adt.internal.wizards.templates.TemplateHandler.TAG_THUMB; + +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; +import com.android.ide.eclipse.adt.AdtPlugin; + +import org.w3c.dom.Attr; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** An ADT template along with metadata */ +class TemplateMetadata { + private final Document mDocument; + private final List<Parameter> mParameters; + private final Map<String, Parameter> mParameterMap; + + TemplateMetadata(@NonNull Document document) { + mDocument = document; + + NodeList parameters = mDocument.getElementsByTagName(TAG_PARAMETER); + mParameters = new ArrayList<Parameter>(parameters.getLength()); + mParameterMap = new HashMap<String, Parameter>(parameters.getLength()); + for (int index = 0, max = parameters.getLength(); index < max; index++) { + Element element = (Element) parameters.item(index); + Parameter parameter = new Parameter(element); + mParameters.add(parameter); + if (parameter.id != null) { + mParameterMap.put(parameter.id, parameter); + } + } + } + + @Nullable + String getTitle() { + String name = mDocument.getDocumentElement().getAttribute(ATTR_NAME); + if (name != null && !name.isEmpty()) { + return name; + } + + return null; + } + + @Nullable + String getDescription() { + String description = mDocument.getDocumentElement().getAttribute(ATTR_DESCRIPTION); + if (description != null && !description.isEmpty()) { + return description; + } + + return null; + } + + @Nullable + String getThumbnailPath() { + // Apply selector logic. Pick the thumb first thumb that satisfies the largest number + // of conditions. + NodeList thumbs = mDocument.getElementsByTagName(TAG_THUMB); + if (thumbs.getLength() == 0) { + return null; + } + + + int bestMatchCount = 0; + Element bestMatch = null; + + for (int i = 0, n = thumbs.getLength(); i < n; i++) { + Element thumb = (Element) thumbs.item(i); + + NamedNodeMap attributes = thumb.getAttributes(); + if (bestMatch == null && attributes.getLength() == 0) { + bestMatch = thumb; + } else if (attributes.getLength() <= bestMatchCount) { + // Already have a match with this number of attributes, no point checking + continue; + } else { + boolean match = true; + for (int j = 0, max = attributes.getLength(); j < max; j++) { + Attr attribute = (Attr) attributes.item(j); + Parameter parameter = mParameterMap.get(attribute.getName()); + if (parameter == null) { + AdtPlugin.log(null, "Unexpected parameter in template thumbnail: %1$s", + attribute.getName()); + continue; + } + String thumbNailValue = attribute.getValue(); + String editedValue = parameter.value != null ? parameter.value.toString() : ""; + if (!thumbNailValue.equals(editedValue)) { + match = false; + break; + } + } + if (match) { + bestMatch = thumb; + bestMatchCount = attributes.getLength(); + } + } + } + + if (bestMatch != null) { + NodeList children = bestMatch.getChildNodes(); + for (int i = 0, n = children.getLength(); i < n; i++) { + Node child = children.item(i); + if (child.getNodeType() == Node.TEXT_NODE) { + return child.getNodeValue().trim(); + } + } + } + + return null; + } + + /** Returns the list of available parameters */ + @NonNull + List<Parameter> getParameters() { + return mParameters; + } +} diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/templates/BlankActivity/template.xml b/eclipse/plugins/com.android.ide.eclipse.adt/templates/BlankActivity/template.xml index 6294592..302e2cc 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/templates/BlankActivity/template.xml +++ b/eclipse/plugins/com.android.ide.eclipse.adt/templates/BlankActivity/template.xml @@ -1,8 +1,7 @@ <?xml version="1.0"?> <template name="New Blank Activity" - description="Creates a new blank activity, with optional inner navigation." - thumb="template_blank_activity.png"> + description="Creates a new blank activity, with optional inner navigation."> <category value="Activities" /> @@ -30,11 +29,11 @@ type="enum" default="none" help="The type of navigation to use for the activity" > - <option id="none" default="true" thumb="template_blank_activity.png">None</option> - <option id="tabs" thumb="template_blank_activity_tabs.png">Tabs</option> - <option id="tabs_pager" thumb="template_blank_activity_tabs_pager.png">Tabs + Swipe</option> - <option id="pager_strip" thumb="template_blank_activity_pager.png">Swipe Views + Title Strip</option> - <option id="dropdown" thumb="template_blank_activity_dropdown.png">Dropdown</option> + <option id="none" default="true">None</option> + <option id="tabs">Tabs</option> + <option id="tabs_pager">Tabs + Swipe</option> + <option id="pager_strip">Swipe Views + Title Strip</option> + <option id="dropdown">Dropdown</option> </parameter> <parameter @@ -52,6 +51,18 @@ constraints="package" default="com.mycompany.myapp" /> + <!-- 128x128 thumbnails relative to template.xml --> + <thumbs> + <!-- default thumbnail is required --> + <thumb>template_blank_activity.png</thumb> + <!-- attributes act as selectors based on chosen parameters --> + <thumb navType="none">template_blank_activity.png</thumb> + <thumb navType="tabs">template_blank_activity_tabs.png</thumb> + <thumb navType="tabs_pager">template_blank_activity_tabs_pager.png</thumb> + <thumb navType="pager_strip">template_blank_activity_pager.png</thumb> + <thumb navType="dropdown">template_blank_activity_dropdown.png</thumb> + </thumbs> + <globals file="globals.xml.ftl" /> <execute file="recipe.xml.ftl" /> diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/templates/MasterDetailFlow/template.xml b/eclipse/plugins/com.android.ide.eclipse.adt/templates/MasterDetailFlow/template.xml index bc01747..0eed682 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/templates/MasterDetailFlow/template.xml +++ b/eclipse/plugins/com.android.ide.eclipse.adt/templates/MasterDetailFlow/template.xml @@ -1,8 +1,11 @@ <?xml version="1.0"?> <template name="New Master/Detail Flow" - description="Creates a new master/detail flow, which is two columns on tablets, and one column on smaller screens. This creates a master fragment, detail fragment, and two activities." - thumb="template_master_detail.png"> + description="Creates a new master/detail flow, which is two columns on tablets, and one column on smaller screens. This creates a master fragment, detail fragment, and two activities."> + + <thumbs> + <thumb>template_master_detail.png</thumb> + </thumbs> <category value="Flows" /> diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/templates/NewAndroidApplication/template.xml b/eclipse/plugins/com.android.ide.eclipse.adt/templates/NewAndroidApplication/template.xml index 60f5363..84ba6c7 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/templates/NewAndroidApplication/template.xml +++ b/eclipse/plugins/com.android.ide.eclipse.adt/templates/NewAndroidApplication/template.xml @@ -1,8 +1,11 @@ <?xml version="1.0"?> <template name="New Android Application" - description="Creates a new Android application with an activity." - thumb="template_new_project.png">> + description="Creates a new Android application with an activity."> + + <thumbs> + <thumb>template_new_project.png</thumb> + </thumbs> <category value="Applications" /> diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/.settings/org.eclipse.jdt.core.prefs b/eclipse/plugins/com.android.ide.eclipse.tests/.settings/org.eclipse.jdt.core.prefs index 5381a0e..bc45534 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/.settings/org.eclipse.jdt.core.prefs +++ b/eclipse/plugins/com.android.ide.eclipse.tests/.settings/org.eclipse.jdt.core.prefs @@ -1,9 +1,10 @@ eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.annotation.missingNonNullByDefaultAnnotation=ignore org.eclipse.jdt.core.compiler.annotation.nonnull=com.android.annotations.NonNull org.eclipse.jdt.core.compiler.annotation.nonnullbydefault=com.android.annotations.NonNullByDefault org.eclipse.jdt.core.compiler.annotation.nonnullisdefault=disabled org.eclipse.jdt.core.compiler.annotation.nullable=com.android.annotations.Nullable -org.eclipse.jdt.core.compiler.annotation.nullanalysis=enabled +org.eclipse.jdt.core.compiler.annotation.nullanalysis=disabled org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve @@ -36,7 +37,9 @@ org.eclipse.jdt.core.compiler.problem.incompleteEnumSwitch=ignore org.eclipse.jdt.core.compiler.problem.indirectStaticAccess=ignore org.eclipse.jdt.core.compiler.problem.localVariableHiding=warning org.eclipse.jdt.core.compiler.problem.methodWithConstructorName=warning +org.eclipse.jdt.core.compiler.problem.missingDefaultCase=ignore org.eclipse.jdt.core.compiler.problem.missingDeprecatedAnnotation=warning +org.eclipse.jdt.core.compiler.problem.missingEnumCaseDespiteDefault=disabled org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=error org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled @@ -45,9 +48,11 @@ org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignor org.eclipse.jdt.core.compiler.problem.noEffectAssignment=warning org.eclipse.jdt.core.compiler.problem.noImplicitStringConversion=warning org.eclipse.jdt.core.compiler.problem.nonExternalizedStringLiteral=ignore +org.eclipse.jdt.core.compiler.problem.nullAnnotationInferenceConflict=error org.eclipse.jdt.core.compiler.problem.nullReference=error org.eclipse.jdt.core.compiler.problem.nullSpecInsufficientInfo=warning org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error +org.eclipse.jdt.core.compiler.problem.nullUncheckedConversion=warning org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/HyperlinksTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/HyperlinksTest.java index 0d42357..a54376d 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/HyperlinksTest.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/HyperlinksTest.java @@ -19,8 +19,6 @@ import static com.android.sdklib.SdkConstants.FD_SOURCES; import com.android.ide.common.resources.ResourceFile; import com.android.ide.eclipse.adt.AdtUtils; -import com.android.ide.eclipse.adt.internal.editors.AndroidXmlEditor; -import com.android.ide.eclipse.adt.internal.editors.Hyperlinks; import com.android.ide.eclipse.adt.internal.editors.Hyperlinks.ResourceLink; import com.android.ide.eclipse.adt.internal.editors.Hyperlinks.XmlResolver; import com.android.ide.eclipse.adt.internal.editors.layout.refactoring.AdtProjectTest; @@ -180,6 +178,12 @@ public class HyperlinksTest extends AdtProjectTest { "class=\"com.and^roid.eclipse.tests.TestFragment\""); } + public void testNavigate15() throws Exception { + // Check navigating to a theme resource + checkXmlNavigation("navigation1.xml", "res/layout/navigation1.xml", + "?android:attr/alert^DialogStyle"); + } + // Left to test: // onClick handling // class attributes diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/navigation1-expected-navigate15.txt b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/navigation1-expected-navigate15.txt new file mode 100644 index 0000000..e36c5f3 --- /dev/null +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/navigation1-expected-navigate15.txt @@ -0,0 +1,7 @@ +Go To Declaration in navigation1.xml for ?android:attr/alert^DialogStyle: +Open Declaration in values/attrs.xml : [?android:attr/alertDialogStyle] + data/res/values/attrs.xml + + +After open, the selected text is: + <attr name="alertDialogStyle" format="reference" />^ diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/navigation1.xml b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/navigation1.xml index 9c175fc..e7ac4bc 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/navigation1.xml +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/editors/layout/refactoring/testdata/navigation1.xml @@ -13,4 +13,5 @@ <EditText android:text="@android:string/ok" </EditText> + <EditText android:text="?android:attr/alertDialogStyle" /> </LinearLayout> diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/lint/ProjectLintConfigurationTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/lint/ProjectLintConfigurationTest.java index 202d768..9f0783f 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/lint/ProjectLintConfigurationTest.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/src/com/android/ide/eclipse/adt/internal/lint/ProjectLintConfigurationTest.java @@ -15,6 +15,8 @@ */ package com.android.ide.eclipse.adt.internal.lint; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.ide.eclipse.adt.internal.editors.layout.refactoring.AdtProjectTest; import com.android.tools.lint.checks.DuplicateIdDetector; import com.android.tools.lint.checks.UnusedResourceDetector; @@ -208,12 +210,14 @@ public class ProjectLintConfigurationTest extends AdtProjectTest { private static class TestClient extends LintClient { @Override - public void report(Context context, Issue issue, Severity severity, Location location, - String message, Object data) { + public void report(@NonNull Context context, @NonNull Issue issue, + @NonNull Severity severity, @Nullable Location location, + @NonNull String message, @Nullable Object data) { } @Override - public void log(Severity severity, Throwable exception, String format, Object... args) { + public void log(@NonNull Severity severity, @Nullable Throwable exception, + @Nullable String format, @Nullable Object... args) { } @Override @@ -222,7 +226,7 @@ public class ProjectLintConfigurationTest extends AdtProjectTest { } @Override - public String readFile(File file) { + public @NonNull String readFile(@NonNull File file) { return null; } diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/LayoutTestBase.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/LayoutTestBase.java index e382132..312df7d 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/LayoutTestBase.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/LayoutTestBase.java @@ -19,6 +19,8 @@ package com.android.ide.common.layout; import static com.android.util.XmlUtils.ANDROID_URI; import static com.android.ide.common.layout.LayoutConstants.ATTR_ID; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.ide.common.api.DropFeedback; import com.android.ide.common.api.IClientRulesEngine; import com.android.ide.common.api.IDragElement; @@ -198,47 +200,48 @@ public class LayoutTestBase extends TestCase { } @Override - public void debugPrintf(String msg, Object... params) { + public void debugPrintf(@NonNull String msg, Object... params) { fail("Not supported in tests yet"); } @Override - public void displayAlert(String message) { + public void displayAlert(@NonNull String message) { fail("Not supported in tests yet"); } @Override - public String displayInput(String message, String value, IValidator filter) { + public String displayInput(@NonNull String message, @Nullable String value, + @Nullable IValidator filter) { fail("Not supported in tests yet"); return null; } @Override - public String getFqcn() { + public @NonNull String getFqcn() { return mFqn; } @Override - public IViewMetadata getMetadata(final String fqcn) { + public @NonNull IViewMetadata getMetadata(final @NonNull String fqcn) { return new IViewMetadata() { @Override - public String getDisplayName() { + public @NonNull String getDisplayName() { // This also works when there is no "." return fqcn.substring(fqcn.lastIndexOf('.') + 1); } @Override - public FillPreference getFillPreference() { + public @NonNull FillPreference getFillPreference() { return ViewMetadataRepository.get().getFillPreference(fqcn); } @Override - public Margins getInsets() { + public @NonNull Margins getInsets() { return null; } @Override - public List<String> getTopAttributes() { + public @NonNull List<String> getTopAttributes() { return ViewMetadataRepository.get().getTopAttributes(fqcn); } }; @@ -250,7 +253,7 @@ public class LayoutTestBase extends TestCase { } @Override - public IViewRule loadRule(String fqcn) { + public IViewRule loadRule(@NonNull String fqcn) { fail("Not supported in tests yet"); return null; } @@ -262,20 +265,21 @@ public class LayoutTestBase extends TestCase { } @Override - public IValidator getResourceValidator() { + public @NonNull IValidator getResourceValidator() { fail("Not supported in tests yet"); return null; } @Override - public String displayResourceInput(String resourceTypeName, String currentValue) { + public String displayResourceInput(@NonNull String resourceTypeName, + @Nullable String currentValue) { fail("Not supported in tests yet"); return null; } @Override - public String[] displayMarginInput(String all, String left, String right, String top, - String bottom) { + public String[] displayMarginInput(@Nullable String all, @Nullable String left, + @Nullable String right, @Nullable String top, @Nullable String bottom) { fail("Not supported in tests yet"); return null; } @@ -287,7 +291,7 @@ public class LayoutTestBase extends TestCase { } @Override - public void select(Collection<INode> nodes) { + public void select(@NonNull Collection<INode> nodes) { fail("Not supported in tests yet"); } @@ -308,7 +312,8 @@ public class LayoutTestBase extends TestCase { } @Override - public Map<INode, Rect> measureChildren(INode parent, AttributeFilter filter) { + public Map<INode, Rect> measureChildren(@NonNull INode parent, + @Nullable AttributeFilter filter) { return null; } @@ -319,7 +324,7 @@ public class LayoutTestBase extends TestCase { } @Override - public String getUniqueId(String prefix) { + public @NonNull String getUniqueId(@NonNull String prefix) { fail("Not supported in tests yet"); return null; } @@ -337,7 +342,7 @@ public class LayoutTestBase extends TestCase { } @Override - public String getAppNameSpace() { + public @NonNull String getAppNameSpace() { fail("Not supported in tests yet"); return null; } diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestAttribute.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestAttribute.java index a1a2af7..76840b1 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestAttribute.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestAttribute.java @@ -15,6 +15,7 @@ */ package com.android.ide.common.layout; +import com.android.annotations.NonNull; import com.android.ide.common.api.IDragElement.IDragAttribute; import com.android.ide.common.api.INode.IAttribute; import com.android.ide.eclipse.adt.internal.editors.uimodel.UiAttributeNode; @@ -35,17 +36,17 @@ public class TestAttribute implements IAttribute, IDragAttribute { } @Override - public String getName() { + public @NonNull String getName() { return mName; } @Override - public String getUri() { + public @NonNull String getUri() { return mUri; } @Override - public String getValue() { + public @NonNull String getValue() { return mValue; } diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestAttributeInfo.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestAttributeInfo.java index f4f83c1..69984bd 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestAttributeInfo.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestAttributeInfo.java @@ -15,6 +15,7 @@ */ package com.android.ide.common.layout; +import com.android.annotations.NonNull; import com.android.ide.common.api.IAttributeInfo; import java.util.EnumSet; @@ -59,22 +60,22 @@ public class TestAttributeInfo implements IAttributeInfo { } @Override - public EnumSet<Format> getFormats() { + public @NonNull EnumSet<Format> getFormats() { return mFormats; } @Override - public String getJavaDoc() { + public @NonNull String getJavaDoc() { return mJavadoc; } @Override - public String getName() { + public @NonNull String getName() { return mName; } @Override - public String getDefinedBy() { + public @NonNull String getDefinedBy() { return mDefinedBy; } }
\ No newline at end of file diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestDragElement.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestDragElement.java index 4a3b4e8..eb0a432 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestDragElement.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestDragElement.java @@ -18,6 +18,8 @@ package com.android.ide.common.layout; import static com.android.util.XmlUtils.ANDROID_URI; import static com.android.ide.common.layout.LayoutConstants.ATTR_ID; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.ide.common.api.IDragElement; import com.android.ide.common.api.Rect; @@ -100,7 +102,7 @@ public class TestDragElement implements IDragElement { // ==== IDragElement ==== @Override - public IDragAttribute getAttribute(String uri, String localName) { + public IDragAttribute getAttribute(@Nullable String uri, @NonNull String localName) { if (mAttributes == null) { return new TestAttribute(uri, localName, ""); } @@ -109,22 +111,22 @@ public class TestDragElement implements IDragElement { } @Override - public IDragAttribute[] getAttributes() { + public @NonNull IDragAttribute[] getAttributes() { return mAttributes.values().toArray(new IDragAttribute[mAttributes.size()]); } @Override - public Rect getBounds() { + public @NonNull Rect getBounds() { return mRect; } @Override - public String getFqcn() { + public @NonNull String getFqcn() { return mFqcn; } @Override - public IDragElement[] getInnerElements() { + public @NonNull IDragElement[] getInnerElements() { if (mChildren == null) { return new IDragElement[0]; } @@ -133,7 +135,7 @@ public class TestDragElement implements IDragElement { } @Override - public Rect getParentBounds() { + public @NonNull Rect getParentBounds() { return mParent != null ? mParent.getBounds() : null; } diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestGraphics.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestGraphics.java index 04f6259..ec93210 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestGraphics.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestGraphics.java @@ -16,6 +16,7 @@ package com.android.ide.common.layout; +import com.android.annotations.NonNull; import com.android.ide.common.api.DrawingStyle; import com.android.ide.common.api.IColor; import com.android.ide.common.api.IGraphics; @@ -51,7 +52,7 @@ public class TestGraphics implements IGraphics { // ==== IGraphics ==== @Override - public void drawBoxedStrings(int x, int y, List<?> strings) { + public void drawBoxedStrings(int x, int y, @NonNull List<?> strings) { mDrawn.add("drawBoxedStrings(" + x + "," + y + "," + strings + ")"); } @@ -61,7 +62,7 @@ public class TestGraphics implements IGraphics { } @Override - public void drawLine(Point p1, Point p2) { + public void drawLine(@NonNull Point p1, @NonNull Point p2) { mDrawn.add("drawLine(" + p1 + "," + p2 + ")"); } @@ -71,22 +72,22 @@ public class TestGraphics implements IGraphics { } @Override - public void drawRect(Point p1, Point p2) { + public void drawRect(@NonNull Point p1, @NonNull Point p2) { mDrawn.add("drawRect(" + p1 + "," + p2 + ")"); } @Override - public void drawRect(Rect r) { + public void drawRect(@NonNull Rect r) { mDrawn.add("drawRect(" + rectToString(r) + ")"); } @Override - public void drawString(String string, int x, int y) { + public void drawString(@NonNull String string, int x, int y) { mDrawn.add("drawString(" + x + "," + y + "," + string + ")"); } @Override - public void drawString(String string, Point topLeft) { + public void drawString(@NonNull String string, @NonNull Point topLeft) { mDrawn.add("drawString(" + string + "," + topLeft + ")"); } @@ -96,12 +97,12 @@ public class TestGraphics implements IGraphics { } @Override - public void fillRect(Point p1, Point p2) { + public void fillRect(@NonNull Point p1, @NonNull Point p2) { mDrawn.add("fillRect(" + p1 + "," + p2 + ")"); } @Override - public void fillRect(Rect r) { + public void fillRect(@NonNull Rect r) { mDrawn.add("fillRect(" + rectToString(r) + ")"); } @@ -111,7 +112,7 @@ public class TestGraphics implements IGraphics { } @Override - public IColor getBackground() { + public @NonNull IColor getBackground() { return mBackground; } @@ -121,12 +122,12 @@ public class TestGraphics implements IGraphics { } @Override - public IColor getForeground() { + public @NonNull IColor getForeground() { return mForeground; } @Override - public IColor registerColor(int rgb) { + public @NonNull IColor registerColor(int rgb) { mDrawn.add("registerColor(" + Integer.toHexString(rgb) + ")"); return new TestColor(rgb); } @@ -138,19 +139,19 @@ public class TestGraphics implements IGraphics { } @Override - public void setBackground(IColor color) { + public void setBackground(@NonNull IColor color) { mDrawn.add("setBackground(" + color + ")"); mBackground = color; } @Override - public void setForeground(IColor color) { + public void setForeground(@NonNull IColor color) { mDrawn.add("setForeground(" + color + ")"); mForeground = color; } @Override - public void setLineStyle(LineStyle style) { + public void setLineStyle(@NonNull LineStyle style) { mDrawn.add("setLineStyle(" + style + ")"); } @@ -160,7 +161,7 @@ public class TestGraphics implements IGraphics { } @Override - public void useStyle(DrawingStyle style) { + public void useStyle(@NonNull DrawingStyle style) { mDrawn.add("useStyle(" + style + ")"); } diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestNode.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestNode.java index 575c958..8984f38 100644 --- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestNode.java +++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/common/layout/TestNode.java @@ -18,6 +18,8 @@ package com.android.ide.common.layout; import static com.android.util.XmlUtils.ANDROID_URI; import static com.android.ide.common.layout.LayoutConstants.ATTR_ID; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.ide.common.api.IAttributeInfo; import com.android.ide.common.api.INode; import com.android.ide.common.api.INodeHandler; @@ -94,12 +96,12 @@ public class TestNode implements INode { // ==== INODE ==== @Override - public INode appendChild(String viewFqcn) { + public @NonNull INode appendChild(@NonNull String viewFqcn) { return insertChildAt(viewFqcn, mChildren.size()); } @Override - public void editXml(String undoName, INodeHandler callback) { + public void editXml(@NonNull String undoName, @NonNull INodeHandler callback) { callback.handle(this); } @@ -108,32 +110,32 @@ public class TestNode implements INode { } @Override - public IAttributeInfo getAttributeInfo(String uri, String attrName) { + public IAttributeInfo getAttributeInfo(@Nullable String uri, @NonNull String attrName) { return mAttributeInfos.get(uri + attrName); } @Override - public Rect getBounds() { + public @NonNull Rect getBounds() { return mBounds; } @Override - public INode[] getChildren() { + public @NonNull INode[] getChildren() { return mChildren.toArray(new INode[mChildren.size()]); } @Override - public IAttributeInfo[] getDeclaredAttributes() { + public @NonNull IAttributeInfo[] getDeclaredAttributes() { return mAttributeInfos.values().toArray(new IAttributeInfo[mAttributeInfos.size()]); } @Override - public String getFqcn() { + public @NonNull String getFqcn() { return mFqcn; } @Override - public IAttribute[] getLiveAttributes() { + public @NonNull IAttribute[] getLiveAttributes() { return mAttributes.values().toArray(new IAttribute[mAttributes.size()]); } @@ -153,7 +155,7 @@ public class TestNode implements INode { } @Override - public String getStringAttr(String uri, String attrName) { + public String getStringAttr(@Nullable String uri, @NonNull String attrName) { IAttribute attr = mAttributes.get(uri + attrName); if (attr == null) { return null; @@ -163,7 +165,7 @@ public class TestNode implements INode { } @Override - public INode insertChildAt(String viewFqcn, int index) { + public @NonNull INode insertChildAt(@NonNull String viewFqcn, int index) { TestNode child = new TestNode(viewFqcn); if (index == -1) { mChildren.add(child); @@ -175,7 +177,7 @@ public class TestNode implements INode { } @Override - public void removeChild(INode node) { + public void removeChild(@NonNull INode node) { int index = mChildren.indexOf(node); if (index != -1) { removeChild(index); @@ -183,7 +185,8 @@ public class TestNode implements INode { } @Override - public boolean setAttribute(String uri, String localName, String value) { + public boolean setAttribute(@Nullable String uri, @NonNull String localName, + @Nullable String value) { mAttributes.put(uri + localName, new TestAttribute(uri, localName, value)); return true; } @@ -200,12 +203,12 @@ public class TestNode implements INode { } @Override - public Margins getMargins() { + public @NonNull Margins getMargins() { return null; } @Override - public List<String> getAttributeSources() { + public @NonNull List<String> getAttributeSources() { return mAttributeSources != null ? mAttributeSources : Collections.<String>emptyList(); } diff --git a/files/ant/build.xml b/files/ant/build.xml index 1f85f5e..cd1bc7d 100644 --- a/files/ant/build.xml +++ b/files/ant/build.xml @@ -648,7 +648,8 @@ nonConstantId="${android.library}" libraryResFolderPathRefid="project.library.res.folder.path" libraryPackagesRefid="project.library.packages" - ignoreAssets="${aapt.ignore.assets}"> + ignoreAssets="${aapt.ignore.assets}" + proguardFile="${out.absolute.dir}/proguard.txt"> <res path="${out.res.absolute.dir}" /> <res path="${resource.absolute.dir}" /> </aapt> @@ -821,6 +822,7 @@ destfile="${preobfuscate.jar.file}" /> <proguard> -include "${proguard.configcmd}" + -include "${out.absolute.dir}/proguard.txt" -injars ${project.all.classes.value} -outjars "${obfuscated.jar.file}" -libraryjars ${project.target.classpath.value} diff --git a/files/proguard-android.txt b/files/proguard-android.txt index 6613823..3cc5c8a 100644 --- a/files/proguard-android.txt +++ b/files/proguard-android.txt @@ -24,15 +24,7 @@ # file from your project's proguard.config path property. -keepattributes *Annotation* --keep public class * extends android.app.Activity --keep public class * extends android.app.Application --keep public class * extends android.app.Service --keep public class * extends android.content.BroadcastReceiver --keep public class * extends android.content.ContentProvider --keep public class * extends android.app.backup.BackupAgent --keep public class * extends android.preference.Preference --keep public class * extends android.support.v4.app.Fragment --keep public class * extends android.app.Fragment +-keep public class com.google.vending.licensing.ILicensingService -keep public class com.android.vending.licensing.ILicensingService # For native methods, see http://proguard.sourceforge.net/manual/examples.html#native @@ -40,21 +32,14 @@ native <methods>; } --keep public class * extends android.view.View { - public <init>(android.content.Context); - public <init>(android.content.Context, android.util.AttributeSet); - public <init>(android.content.Context, android.util.AttributeSet, int); - public void set*(...); -} - --keepclasseswithmembers class * { - public <init>(android.content.Context, android.util.AttributeSet); -} - --keepclasseswithmembers class * { - public <init>(android.content.Context, android.util.AttributeSet, int); +# keep setters in Views so that animations can still work. +# see http://proguard.sourceforge.net/manual/examples.html#beans +-keepclassmembers public class * extends android.view.View { + void set*(***); + *** get*(); } +# We want to keep methods in Activity that could be used in the XML attribute onClick -keepclassmembers class * extends android.app.Activity { public void *(android.view.View); } diff --git a/lint/cli/src/com/android/tools/lint/LintCliXmlParser.java b/lint/cli/src/com/android/tools/lint/LintCliXmlParser.java index e777e99..c13c41d 100644 --- a/lint/cli/src/com/android/tools/lint/LintCliXmlParser.java +++ b/lint/cli/src/com/android/tools/lint/LintCliXmlParser.java @@ -16,6 +16,7 @@ package com.android.tools.lint; +import com.android.annotations.NonNull; import com.android.annotations.Nullable; import com.android.tools.lint.client.api.IDomParser; import com.android.tools.lint.client.api.IssueRegistry; @@ -40,7 +41,7 @@ import java.io.UnsupportedEncodingException; */ public class LintCliXmlParser extends PositionXmlParser implements IDomParser { @Override - public Document parseXml(XmlContext context) { + public Document parseXml(@NonNull XmlContext context) { try { // Do we need to provide an input stream for encoding? String xml = context.getContents(); @@ -70,22 +71,22 @@ public class LintCliXmlParser extends PositionXmlParser implements IDomParser { } @Override - public Location getLocation(XmlContext context, Node node) { + public @NonNull Location getLocation(@NonNull XmlContext context, @NonNull Node node) { OffsetPosition pos = (OffsetPosition) getPosition(node); if (pos != null) { return Location.create(context.file, pos, (OffsetPosition) pos.getEnd()); } - return null; + return Location.create(context.file); } @Override - public Handle createLocationHandle(XmlContext context, Node node) { + public @NonNull Handle createLocationHandle(@NonNull XmlContext context, @NonNull Node node) { return new LocationHandle(context.file, node); } @Override - protected OffsetPosition createPosition(int line, int column, int offset) { + protected @NonNull OffsetPosition createPosition(int line, int column, int offset) { return new OffsetPosition(line, column, offset); } @@ -143,7 +144,7 @@ public class LintCliXmlParser extends PositionXmlParser implements IDomParser { } @Override - public void setEnd(com.android.util.PositionXmlParser.Position end) { + public void setEnd(@NonNull com.android.util.PositionXmlParser.Position end) { mEnd = end; } @@ -155,7 +156,7 @@ public class LintCliXmlParser extends PositionXmlParser implements IDomParser { } @Override - public void dispose(XmlContext context, Document document) { + public void dispose(@NonNull XmlContext context, @NonNull Document document) { } /* Handle for creating DOM positions cheaply and returning full fledged locations later */ @@ -170,13 +171,13 @@ public class LintCliXmlParser extends PositionXmlParser implements IDomParser { } @Override - public Location resolve() { + public @NonNull Location resolve() { OffsetPosition pos = (OffsetPosition) getPosition(mNode); if (pos != null) { return Location.create(mFile, pos, (OffsetPosition) pos.getEnd()); } - return null; + return Location.create(mFile); } @Override diff --git a/lint/cli/src/com/android/tools/lint/LombokParser.java b/lint/cli/src/com/android/tools/lint/LombokParser.java index 15b1073..2c263c6 100644 --- a/lint/cli/src/com/android/tools/lint/LombokParser.java +++ b/lint/cli/src/com/android/tools/lint/LombokParser.java @@ -16,6 +16,7 @@ package com.android.tools.lint; +import com.android.annotations.NonNull; import com.android.annotations.Nullable; import com.android.tools.lint.client.api.IJavaParser; import com.android.tools.lint.detector.api.JavaContext; @@ -39,7 +40,7 @@ import lombok.ast.grammar.Source; public class LombokParser implements IJavaParser { @Override - public Node parseJava(JavaContext context) { + public Node parseJava(@NonNull JavaContext context) { try { Source source = new Source(context.getContents(), context.file.getName()); List<Node> nodes = source.getNodes(); @@ -95,19 +96,21 @@ public class LombokParser implements IJavaParser { } @Override - public Location getLocation(JavaContext context, lombok.ast.Node node) { + public @NonNull Location getLocation( + @NonNull JavaContext context, + @NonNull lombok.ast.Node node) { lombok.ast.Position position = node.getPosition(); return Location.create(context.file, context.getContents(), position.getStart(), position.getEnd()); } @Override - public Handle createLocationHandle(JavaContext context, Node node) { + public @NonNull Handle createLocationHandle(@NonNull JavaContext context, @NonNull Node node) { return new LocationHandle(context.file, node); } @Override - public void dispose(JavaContext context, Node compilationUnit) { + public void dispose(@NonNull JavaContext context, @NonNull Node compilationUnit) { } /* Handle for creating positions cheaply and returning full fledged locations later */ @@ -122,7 +125,7 @@ public class LombokParser implements IJavaParser { } @Override - public Location resolve() { + public @NonNull Location resolve() { Position pos = mNode.getPosition(); return Location.create(mFile, null /*contents*/, pos.getStart(), pos.getEnd()); } diff --git a/lint/cli/src/com/android/tools/lint/Main.java b/lint/cli/src/com/android/tools/lint/Main.java index 6a40cb3..68d68b4 100644 --- a/lint/cli/src/com/android/tools/lint/Main.java +++ b/lint/cli/src/com/android/tools/lint/Main.java @@ -21,6 +21,7 @@ import static com.android.tools.lint.client.api.IssueRegistry.PARSER_ERROR; import static com.android.tools.lint.detector.api.LintConstants.DOT_XML; import static com.android.tools.lint.detector.api.LintUtils.endsWith; +import com.android.annotations.NonNull; import com.android.annotations.Nullable; import com.android.tools.lint.checks.BuiltinIssueRegistry; import com.android.tools.lint.client.api.Configuration; @@ -886,7 +887,11 @@ public class Main extends LintClient { } @Override - public void log(Severity severity, Throwable exception, String format, Object... args) { + public void log( + @NonNull Severity severity, + @Nullable Throwable exception, + @Nullable String format, + @Nullable Object... args) { System.out.flush(); if (!mQuiet) { // Place the error message on a line of its own since we're printing '.' etc @@ -907,7 +912,7 @@ public class Main extends LintClient { } @Override - public Configuration getConfiguration(Project project) { + public Configuration getConfiguration(@NonNull Project project) { return new CliConfiguration(mDefaultConfiguration, project); } @@ -934,8 +939,13 @@ public class Main extends LintClient { } @Override - public void report(Context context, Issue issue, Severity severity, Location location, - String message, Object data) { + public void report( + @NonNull Context context, + @NonNull Issue issue, + @NonNull Severity severity, + @Nullable Location location, + @NonNull String message, + @Nullable Object data) { assert context.isEnabled(issue); if (severity == Severity.IGNORE) { @@ -1041,7 +1051,7 @@ public class Main extends LintClient { } @Override - public String readFile(File file) { + public @NonNull String readFile(@NonNull File file) { try { return LintUtils.getEncodedString(file); } catch (IOException e) { @@ -1067,7 +1077,7 @@ public class Main extends LintClient { } @Override - public Severity getSeverity(Issue issue) { + public @NonNull Severity getSeverity(@NonNull Issue issue) { Severity severity = computeSeverity(issue); if (mAllErrors && severity != Severity.IGNORE) { @@ -1082,7 +1092,7 @@ public class Main extends LintClient { } @Override - protected Severity getDefaultSeverity(Issue issue) { + protected @NonNull Severity getDefaultSeverity(@NonNull Issue issue) { if (mWarnAll) { return issue.getDefaultSeverity(); } @@ -1090,7 +1100,7 @@ public class Main extends LintClient { return super.getDefaultSeverity(issue); } - private Severity computeSeverity(Issue issue) { + private Severity computeSeverity(@NonNull Issue issue) { Severity severity = super.getSeverity(issue); String id = issue.getId(); @@ -1123,25 +1133,32 @@ public class Main extends LintClient { private class ProgressPrinter implements LintListener { @Override - public void update(LintDriver lint, EventType type, Context context) { + public void update( + @NonNull LintDriver lint, + @NonNull EventType type, + @Nullable Context context) { switch (type) { - case SCANNING_PROJECT: + case SCANNING_PROJECT: { + String name = context != null ? context.getProject().getName() : "?"; if (lint.getPhase() > 1) { System.out.print(String.format( "\nScanning %1$s (Phase %2$d): ", - context.getProject().getName(), + name, lint.getPhase())); } else { System.out.print(String.format( "\nScanning %1$s: ", - context.getProject().getName())); + name)); } break; - case SCANNING_LIBRARY_PROJECT: + } + case SCANNING_LIBRARY_PROJECT: { + String name = context != null ? context.getProject().getName() : "?"; System.out.print(String.format( "\n - %1$s: ", - context.getProject().getName())); + name)); break; + } case SCANNING_FILE: System.out.print('.'); break; diff --git a/lint/libs/lint_api/src/com/android/tools/lint/client/api/DefaultConfiguration.java b/lint/libs/lint_api/src/com/android/tools/lint/client/api/DefaultConfiguration.java index 6dc4804..665368c 100644 --- a/lint/libs/lint_api/src/com/android/tools/lint/client/api/DefaultConfiguration.java +++ b/lint/libs/lint_api/src/com/android/tools/lint/client/api/DefaultConfiguration.java @@ -202,7 +202,12 @@ public class DefaultConfiguration extends Configuration { message = String.format(message, args); } message = "Failed to parse lint.xml configuration file: " + message; - mClient.report(new Context(null, mProject, mProject, mConfigFile), + LintDriver driver = new LintDriver(new IssueRegistry() { + @Override @NonNull public List<Issue> getIssues() { + return Collections.emptyList(); + } + }, mClient); + mClient.report(new Context(driver, mProject, mProject, mConfigFile), IssueRegistry.LINT_ERROR, mProject.getConfiguration().getSeverity(IssueRegistry.LINT_ERROR), Location.create(mConfigFile), message, null); diff --git a/lint/libs/lint_api/src/com/android/tools/lint/client/api/IssueRegistry.java b/lint/libs/lint_api/src/com/android/tools/lint/client/api/IssueRegistry.java index 74df385..cf45b2e 100644 --- a/lint/libs/lint_api/src/com/android/tools/lint/client/api/IssueRegistry.java +++ b/lint/libs/lint_api/src/com/android/tools/lint/client/api/IssueRegistry.java @@ -57,7 +57,7 @@ public abstract class IssueRegistry { Category.CORRECTNESS, 10, Severity.ERROR, - null, + Detector.class, Scope.RESOURCE_FILE_SCOPE); /** @@ -78,7 +78,7 @@ public abstract class IssueRegistry { Category.LINT, 10, Severity.ERROR, - null, + Detector.class, Scope.RESOURCE_FILE_SCOPE); /** diff --git a/lint/libs/lint_api/src/com/android/tools/lint/client/api/JavaVisitor.java b/lint/libs/lint_api/src/com/android/tools/lint/client/api/JavaVisitor.java index 1dbf915..3b641d0 100644 --- a/lint/libs/lint_api/src/com/android/tools/lint/client/api/JavaVisitor.java +++ b/lint/libs/lint_api/src/com/android/tools/lint/client/api/JavaVisitor.java @@ -1172,7 +1172,7 @@ public class JavaVisitor { } @Override - public boolean visitMethodInvocation(@NonNull MethodInvocation node) { + public boolean visitMethodInvocation(MethodInvocation node) { if (mVisitMethods) { String methodName = node.astName().getDescription(); List<VisitingDetector> list = mMethodDetectors.get(methodName); diff --git a/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintClient.java b/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintClient.java index 8d6367b..93e311e 100644 --- a/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintClient.java +++ b/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintClient.java @@ -16,15 +16,23 @@ package com.android.tools.lint.client.api; +import static com.android.tools.lint.detector.api.LintConstants.CLASS_FOLDER; +import static com.android.tools.lint.detector.api.LintConstants.DOT_JAR; +import static com.android.tools.lint.detector.api.LintConstants.GEN_FOLDER; +import static com.android.tools.lint.detector.api.LintConstants.LIBS_FOLDER; +import static com.android.tools.lint.detector.api.LintConstants.SRC_FOLDER; + import com.android.annotations.NonNull; import com.android.annotations.Nullable; import com.android.tools.lint.detector.api.Context; import com.android.tools.lint.detector.api.Detector; 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.Project; import com.android.tools.lint.detector.api.Severity; import com.google.common.annotations.Beta; +import com.google.common.collect.Maps; import org.w3c.dom.Document; import org.w3c.dom.Element; @@ -53,7 +61,6 @@ import javax.xml.parsers.DocumentBuilderFactory; */ @Beta public abstract class LintClient { - private static final String PROP_BIN_DIR = "com.android.tools.lint.bindir"; //$NON-NLS-1$ /** @@ -177,7 +184,7 @@ public abstract class LintClient { */ @NonNull public List<File> getJavaSourceFolders(@NonNull Project project) { - return getEclipseClasspath(project, "src", "src", "gen"); //$NON-NLS-1$ //$NON-NLS-2$ + return getClassPath(project).getSourceFolders(); } /** @@ -188,7 +195,8 @@ public abstract class LintClient { */ @NonNull public List<File> getJavaClassFolders(@NonNull Project project) { - return getEclipseClasspath(project, "output", "bin"); //$NON-NLS-1$ //$NON-NLS-2$ + return getClassPath(project).getClassFolders(); + } /** @@ -199,7 +207,7 @@ public abstract class LintClient { */ @NonNull public List<File> getJavaLibraries(@NonNull Project project) { - return getEclipseClasspath(project, "lib"); //$NON-NLS-1$ + return getClassPath(project).getLibraries(); } /** @@ -224,7 +232,7 @@ public abstract class LintClient { * the create flag was false, or if for some reason the directory * could not be created */ - @NonNull + @Nullable public File getCacheDir(boolean create) { String home = System.getProperty("user.home"); String relative = ".android" + File.separator + "cache"; //$NON-NLS-1$ //$NON-NLS-2$ @@ -286,53 +294,141 @@ public abstract class LintClient { } } + private Map<Project, ClassPathInfo> mProjectInfo; + /** - * Considers the given directory as an Eclipse project and returns either - * its source or its output folders depending on the {@code attribute} parameter. + * Information about class paths (sources, class files and libraries) + * usually associated with a project. + */ + protected static class ClassPathInfo { + private final List<File> mClassFolders; + private final List<File> mSourceFolders; + private final List<File> mLibraries; + + public ClassPathInfo( + @NonNull List<File> sourceFolders, + @NonNull List<File> classFolders, + @NonNull List<File> libraries) { + mSourceFolders = sourceFolders; + mClassFolders = classFolders; + mLibraries = libraries; + } + + @NonNull + public List<File> getSourceFolders() { + return mSourceFolders; + } + + @NonNull + public List<File> getClassFolders() { + return mClassFolders; + } + + @NonNull + public List<File> getLibraries() { + return mLibraries; + } + } + + /** + * Considers the given project as an Eclipse project and returns class path + * information for the project - the source folder(s), the output folder and + * any libraries. + * <p> + * Callers will not cache calls to this method, so if it's expensive to compute + * the classpath info, this method should perform its own caching. + * + * @param project the project to look up class path info for + * @return a class path info object, never null */ @NonNull - private List<File> getEclipseClasspath(@NonNull Project project, @NonNull String attribute, - @NonNull String... fallbackPaths) { - List<File> folders = new ArrayList<File>(); - File projectDir = project.getDir(); - File classpathFile = new File(projectDir, ".classpath"); //$NON-NLS-1$ - if (classpathFile.exists()) { - String classpathXml = readFile(classpathFile); - DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - InputSource is = new InputSource(new StringReader(classpathXml)); - factory.setNamespaceAware(false); - factory.setValidating(false); - try { - DocumentBuilder builder = factory.newDocumentBuilder(); - Document document = builder.parse(is); - NodeList tags = document.getElementsByTagName("classpathentry"); //$NON-NLS-1$ - for (int i = 0, n = tags.getLength(); i < n; i++) { - Element element = (Element) tags.item(i); - String kind = element.getAttribute("kind"); //$NON-NLS-1$ - if (kind.equals(attribute)) { - String path = element.getAttribute("path"); //$NON-NLS-1$ - File sourceFolder = new File(projectDir, path); - if (sourceFolder.exists()) { - folders.add(sourceFolder); + protected ClassPathInfo getClassPath(@NonNull Project project) { + ClassPathInfo info; + if (mProjectInfo == null) { + mProjectInfo = Maps.newHashMap(); + info = null; + } else { + info = mProjectInfo.get(project); + } + + if (info == null) { + List<File> sources = new ArrayList<File>(2); + List<File> classes = new ArrayList<File>(1); + List<File> libraries = new ArrayList<File>(); + + File projectDir = project.getDir(); + File classpathFile = new File(projectDir, ".classpath"); //$NON-NLS-1$ + if (classpathFile.exists()) { + String classpathXml = readFile(classpathFile); + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + InputSource is = new InputSource(new StringReader(classpathXml)); + factory.setNamespaceAware(false); + factory.setValidating(false); + try { + DocumentBuilder builder = factory.newDocumentBuilder(); + Document document = builder.parse(is); + NodeList tags = document.getElementsByTagName("classpathentry"); //$NON-NLS-1$ + for (int i = 0, n = tags.getLength(); i < n; i++) { + Element element = (Element) tags.item(i); + String kind = element.getAttribute("kind"); //$NON-NLS-1$ + List<File> addTo = null; + if (kind.equals("src")) { //$NON-NLS-1$ + addTo = sources; + } else if (kind.equals("output")) { //$NON-NLS-1$ + addTo = classes; + } else if (kind.equals("lib")) { //$NON-NLS-1$ + addTo = libraries; + } + if (addTo != null) { + String path = element.getAttribute("path"); //$NON-NLS-1$ + File folder = new File(projectDir, path); + if (folder.exists()) { + addTo.add(folder); + } + } + } + } catch (Exception e) { + log(null, null); + } + } + + // Add in libraries that aren't specified in the .classpath file + File libs = new File(project.getDir(), LIBS_FOLDER); + if (libs.isDirectory()) { + File[] jars = libs.listFiles(); + if (jars != null) { + for (File jar : jars) { + if (LintUtils.endsWith(jar.getPath(), DOT_JAR) + && !libraries.contains(jar)) { + libraries.add(jar); } } } - } catch (Exception e) { - log(null, null); } - } - // Fallback? - if (folders.size() == 0) { - for (String fallbackPath : fallbackPaths) { - File folder = new File(projectDir, fallbackPath); + // Fallback, in case there is no Eclipse project metadata here + if (sources.size() == 0) { + File src = new File(projectDir, SRC_FOLDER); + if (src.exists()) { + sources.add(src); + } + File gen = new File(projectDir, GEN_FOLDER); + if (gen.exists()) { + sources.add(gen); + } + } + if (classes.size() == 0) { + File folder = new File(projectDir, CLASS_FOLDER); if (folder.exists()) { - folders.add(folder); + classes.add(folder); } } + + info = new ClassPathInfo(sources, classes, libraries); + mProjectInfo.put(project, info); } - return folders; + return info; } /** diff --git a/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintDriver.java b/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintDriver.java index 0f985f0..05c5765 100644 --- a/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintDriver.java +++ b/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintDriver.java @@ -18,6 +18,7 @@ package com.android.tools.lint.client.api; import static com.android.tools.lint.detector.api.LintConstants.ANDROID_MANIFEST_XML; import static com.android.tools.lint.detector.api.LintConstants.ATTR_IGNORE; +import static com.android.tools.lint.detector.api.LintConstants.BIN_FOLDER; import static com.android.tools.lint.detector.api.LintConstants.DOT_CLASS; import static com.android.tools.lint.detector.api.LintConstants.DOT_JAR; import static com.android.tools.lint.detector.api.LintConstants.DOT_JAVA; @@ -537,7 +538,7 @@ public class LintDriver { continue; } else { parent = parent.getParentFile(); - if (isProjectDir(parent)) { + if (parent != null && isProjectDir(parent)) { registerProjectFile(fileToProject, file, parent, parent); continue; } @@ -638,7 +639,22 @@ public class LintDriver { } private boolean isProjectDir(@NonNull File dir) { - return new File(dir, ANDROID_MANIFEST_XML).exists(); + boolean hasManifest = new File(dir, ANDROID_MANIFEST_XML).exists(); + if (hasManifest) { + // Special case: the bin/ folder can also contain a copy of the + // manifest file, but this is *not* a project directory + if (dir.getName().equals(BIN_FOLDER)) { + // ...unless of course it just *happens* to be a project named bin, in + // which case we peek at its parent to see if this is the case + dir = dir.getParentFile(); + if (dir != null && isProjectDir(dir)) { + // Yes, it's a bin/ directory inside a real project: ignore this dir + return false; + } + } + } + + return hasManifest; } private void checkProject(@NonNull Project project) { @@ -702,7 +718,7 @@ public class LintDriver { // Must provide an issue since API guarantees that the issue parameter // is valid Issue.create("Lint", "", "", Category.PERFORMANCE, 0, Severity.INFORMATIONAL, //$NON-NLS-1$ - null, EnumSet.noneOf(Scope.class)), + Detector.class, EnumSet.noneOf(Scope.class)), Severity.INFORMATIONAL, null /*range*/, "Lint canceled by user", null); @@ -746,9 +762,9 @@ public class LintDriver { } } if (xmlDetectors.size() > 0) { - if (project.getSubset() != null) { - checkIndividualResources(project, main, xmlDetectors, - project.getSubset()); + List<File> files = project.getSubset(); + if (files != null) { + checkIndividualResources(project, main, xmlDetectors, files); } else { File res = new File(project.getDir(), RES_FOLDER); if (res.exists() && xmlDetectors.size() > 0) { @@ -767,9 +783,9 @@ public class LintDriver { List<Detector> checks = union(mScopeDetectors.get(Scope.JAVA_FILE), mScopeDetectors.get(Scope.ALL_JAVA_FILES)); if (checks != null && checks.size() > 0) { - if (project.getSubset() != null) { - checkIndividualJavaFiles(project, main, checks, - project.getSubset()); + List<File> files = project.getSubset(); + if (files != null) { + checkIndividualJavaFiles(project, main, checks, files); } else { List<File> sourceFolders = project.getJavaSourceFolders(); checkJava(project, main, sourceFolders, checks); @@ -865,6 +881,30 @@ public class LintDriver { return mSuperClassMap.get(name); } + /** + * Returns true if the given class is a subclass of the given super class. + * + * @param classNode the class to check whether it is a subclass of the given + * super class name + * @param superClassName the fully qualified super class name (in VM format, + * e.g. java/lang/Integer, not java.lang.Integer. + * @return true if the given class is a subclass of the given super class + */ + public boolean isSubclassOf(@NonNull ClassNode classNode, @NonNull String superClassName) { + if (superClassName.equals(classNode.superName)) { + return true; + } + + String className = classNode.name; + while (className != null) { + if (className.equals(superClassName)) { + return true; + } + className = getSuperClass(className); + } + + return false; + } @Nullable private static List<Detector> union( @Nullable List<Detector> list1, @@ -891,8 +931,9 @@ public class LintDriver { /** Check the classes in this project (and if applicable, in any library projects */ private void checkClasses(Project project, Project main) { - if (project.getSubset() != null) { - checkIndividualClassFiles(project, main, project.getSubset()); + List<File> files = project.getSubset(); + if (files != null) { + checkIndividualClassFiles(project, main, files); return; } @@ -977,6 +1018,7 @@ public class LintDriver { } if (entries.size() > 0) { + Collections.sort(entries); // No superclass info available on individual lint runs mSuperClassMap = Collections.emptyMap(); runClassDetectors(Scope.CLASS_FILE, entries, project, main); @@ -1078,7 +1120,8 @@ public class LintDriver { for (ClassEntry entry : entries) { try { ClassReader reader = new ClassReader(entry.bytes); - int flags = ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES; + int flags = ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG + | ClassReader.SKIP_FRAMES; reader.accept(visitor, flags); } catch (Throwable t) { mClient.log(null, "Error processing %1$s: broken class file?", entry.path()); @@ -1304,7 +1347,10 @@ public class LintDriver { return null; } - mCurrentVisitor = new XmlVisitor(mClient.getDomParser(), applicableChecks); + IDomParser parser = mClient.getDomParser(); + if (parser != null) { + mCurrentVisitor = new XmlVisitor(parser, applicableChecks); + } } return mCurrentVisitor; @@ -1425,7 +1471,7 @@ public class LintDriver { } /** Notifies listeners, if any, that the given event has occurred */ - private void fireEvent(@NonNull LintListener.EventType type, @NonNull Context context) { + private void fireEvent(@NonNull LintListener.EventType type, @Nullable Context context) { if (mListeners != null) { for (int i = 0, n = mListeners.size(); i < n; i++) { LintListener listener = mListeners.get(i); @@ -1512,7 +1558,7 @@ public class LintDriver { } @Override - public List<File> getJavaLibraries(Project project) { + public @NonNull List<File> getJavaLibraries(@NonNull Project project) { return mDelegate.getJavaLibraries(project); } @@ -1524,13 +1570,14 @@ public class LintDriver { @Override @NonNull - public Class<? extends Detector> replaceDetector(Class<? extends Detector> detectorClass) { + public Class<? extends Detector> replaceDetector( + @NonNull Class<? extends Detector> detectorClass) { return mDelegate.replaceDetector(detectorClass); } @Override @NonNull - public SdkInfo getSdkInfo(Project project) { + public SdkInfo getSdkInfo(@NonNull Project project) { return mDelegate.getSdkInfo(project); } @@ -1547,7 +1594,7 @@ public class LintDriver { } @Override - public File findResource(String relativePath) { + public File findResource(@NonNull String relativePath) { return mDelegate.findResource(relativePath); } } diff --git a/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintListener.java b/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintListener.java index 777100d..2247a6d 100644 --- a/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintListener.java +++ b/lint/libs/lint_api/src/com/android/tools/lint/client/api/LintListener.java @@ -17,6 +17,7 @@ package com.android.tools.lint.client.api; import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.tools.lint.detector.api.Context; import com.google.common.annotations.Beta; @@ -65,5 +66,5 @@ public interface LintListener { * @param context the context providing additional information */ public void update(@NonNull LintDriver driver, @NonNull EventType type, - @NonNull Context context); + @Nullable Context context); } diff --git a/lint/libs/lint_api/src/com/android/tools/lint/client/api/SdkInfo.java b/lint/libs/lint_api/src/com/android/tools/lint/client/api/SdkInfo.java index b16747c..5ff7f90 100644 --- a/lint/libs/lint_api/src/com/android/tools/lint/client/api/SdkInfo.java +++ b/lint/libs/lint_api/src/com/android/tools/lint/client/api/SdkInfo.java @@ -42,11 +42,12 @@ public abstract class SdkInfo { if (parentViewFqcn.equals(childViewFqcn)) { return true; } - childViewFqcn = getParentViewClass(childViewFqcn); - if (childViewFqcn == null) { + String parent = getParentViewClass(childViewFqcn); + if (parent == null) { // Unknown view - err on the side of caution return true; } + childViewFqcn = parent; } return false; diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Category.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Category.java index 6978ef0..ba8e5b5 100644 --- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Category.java +++ b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Category.java @@ -125,7 +125,7 @@ public final class Category implements Comparable<Category> { } @Override - public int compareTo(@NonNull Category other) { + public int compareTo(Category other) { if (other.mPriority == mPriority) { if (mParent == other) { return 1; diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/ClassContext.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/ClassContext.java index 44d5392..3c6842e 100644 --- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/ClassContext.java +++ b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/ClassContext.java @@ -16,6 +16,7 @@ package com.android.tools.lint.detector.api; +import static com.android.tools.lint.detector.api.LintConstants.CONSTRUCTOR_NAME; import static com.android.tools.lint.detector.api.LintConstants.DOT_CLASS; import static com.android.tools.lint.detector.api.LintConstants.DOT_JAVA; @@ -253,7 +254,11 @@ public class ClassContext extends Context { * @param data any associated data, or null */ @Override - public void report(Issue issue, Location location, String message, Object data) { + public void report( + @NonNull Issue issue, + @Nullable Location location, + @NonNull String message, + @Nullable Object data) { if (mDriver.isSuppressed(issue, mClassNode)) { return; } @@ -444,6 +449,35 @@ public class ClassContext extends Context { return null; } + /** + * Returns a location for the given {@link MethodNode}. + * + * @param methodNode the class in the current context + * @param classNode the class containing the method + * @return a location pointing to the class declaration, or as close to it + * as possible + */ + @NonNull + public Location getLocation(@NonNull MethodNode methodNode, + @NonNull ClassNode classNode) { + // Attempt to find a proper location for this class. This is tricky + // since classes do not have line number entries in the class file; we need + // to find a method, look up the corresponding line number then search + // around it for a suitable tag, such as the class name. + String pattern; + if (methodNode.name.equals(CONSTRUCTOR_NAME)) { + if (isAnonymousClass(classNode.name)) { + pattern = classNode.superName.substring(classNode.superName.lastIndexOf('/') + 1); + } else { + pattern = classNode.name.substring(classNode.name.lastIndexOf('$') + 1); + } + } else { + pattern = methodNode.name; + } + + return getLocationForLine(findLineNumber(methodNode), pattern, null); + } + private static boolean isAnonymousClass(@NonNull String fqcn) { int lastIndex = fqcn.lastIndexOf('$'); if (lastIndex != -1 && lastIndex < fqcn.length() - 1) { diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Detector.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Detector.java index c795606..c8f9fd2 100644 --- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Detector.java +++ b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Detector.java @@ -372,7 +372,9 @@ public abstract class Detector { * @return the expected speed of this detector */ @NonNull - public abstract Speed getSpeed(); + public Speed getSpeed() { + return Speed.NORMAL; + } // ---- Dummy implementations to make implementing XmlScanner easier: ---- diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Issue.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Issue.java index 9f42fb4..0ac8805 100644 --- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Issue.java +++ b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Issue.java @@ -219,7 +219,7 @@ public final class Issue implements Comparable<Issue> { * @param other the {@link Issue} to compare this issue to */ @Override - public int compareTo(@NonNull Issue other) { + public int compareTo(Issue other) { return getId().compareTo(other.getId()); } diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/JavaContext.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/JavaContext.java index d7c1e6e..ae86568 100644 --- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/JavaContext.java +++ b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/JavaContext.java @@ -74,7 +74,8 @@ public class JavaContext extends Context { } @Override - public void report(Issue issue, Location location, String message, Object data) { + public void report(@NonNull Issue issue, @Nullable Location location, + @NonNull String message, @Nullable Object data) { if (mDriver.isSuppressed(issue, compilationUnit)) { return; } diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintConstants.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintConstants.java index a2757cb..3b7d63f 100644 --- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintConstants.java +++ b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintConstants.java @@ -18,6 +18,8 @@ package com.android.tools.lint.detector.api; import com.google.common.annotations.Beta; +import java.io.File; + /** * Constants used by the various detectors, defined in one place * <p> @@ -254,6 +256,12 @@ public class LintConstants { public static final String ANDROID_MANIFEST_XML = "AndroidManifest.xml"; //$NON-NLS-1$ public static final String OLD_PROGUARD_FILE = "proguard.cfg"; //$NON-NLS-1$ public static final String PROGUARD_FILE = "proguard-project.txt"; //$NON-NLS-1$ + public static final String CLASS_FOLDER = + "bin" + File.separator + "classes"; //$NON-NLS-1$ //$NON-NLS-2$ + public static final String GEN_FOLDER = "gen"; //$NON-NLS-1$ + public static final String SRC_FOLDER = "src"; //$NON-NLS-1$ + public static final String LIBS_FOLDER = "libs"; //$NON-NLS-1$ + public static final String BIN_FOLDER = "bin"; //$NON-NLS-1$ public static final String RES_FOLDER = "res"; //$NON-NLS-1$ public static final String DOT_XML = ".xml"; //$NON-NLS-1$ @@ -316,4 +324,9 @@ public class LintConstants { public static final String TARGET_API = "TargetApi"; //$NON-NLS-1$ public static final String FQCN_SUPPRESS_LINT = "android.annotation." + SUPPRESS_LINT; //$NON-NLS-1$ public static final String FQCN_TARGET_API = "android.annotation." + TARGET_API; //$NON-NLS-1$ + + // Class Names + public static final String CONSTRUCTOR_NAME = "<init>"; //$NON-NLS-1$ + public static final String FRAGMENT = "android/app/Fragment"; //$NON-NLS-1$ + public static final String FRAGMENT_V4 = "android/support/v4/app/Fragment"; //$NON-NLS-1$ } diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintUtils.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintUtils.java index eef6d48..ef987f2 100644 --- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintUtils.java +++ b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/LintUtils.java @@ -29,6 +29,9 @@ import com.android.util.PositionXmlParser; import com.google.common.annotations.Beta; import com.google.common.io.Files; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.FieldNode; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; @@ -489,4 +492,28 @@ public class LintUtils { } return text; } + + /** + * Returns true if the given class node represents a static inner class. + * + * @param classNode the inner class to be checked + * @return true if the class node represents an inner class that is static + */ + public static boolean isStaticInnerClass(@NonNull ClassNode classNode) { + // Note: We can't just filter out static inner classes like this: + // (classNode.access & Opcodes.ACC_STATIC) != 0 + // because the static flag only appears on methods and fields in the class + // file. Instead, look for the synthetic this pointer. + + @SuppressWarnings("rawtypes") // ASM API + List fieldList = classNode.fields; + for (Object f : fieldList) { + FieldNode field = (FieldNode) f; + if (field.name.startsWith("this$") && (field.access & Opcodes.ACC_SYNTHETIC) != 0) { + return false; + } + } + + return true; + } } diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Location.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Location.java index 9d61047..167de42 100644 --- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Location.java +++ b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Location.java @@ -110,7 +110,7 @@ public class Location { * * @param secondary a secondary location associated with this location */ - public void setSecondary(@NonNull Location secondary) { + public void setSecondary(@Nullable Location secondary) { this.mSecondary = secondary; } @@ -197,7 +197,7 @@ public class Location { public static Location create( @NonNull File file, @NonNull Position start, - @NonNull Position end) { + @Nullable Position end) { return new Location(file, start, end); } diff --git a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Severity.java b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Severity.java index d0bbd7b..cde61bd 100644 --- a/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Severity.java +++ b/lint/libs/lint_api/src/com/android/tools/lint/detector/api/Severity.java @@ -31,30 +31,36 @@ public enum Severity { * Fatal: Use sparingly because a warning marked as fatal will be * considered critical and will abort Export APK etc in ADT */ + @NonNull FATAL("Fatal"), /** * Errors: The issue is known to be a real error that must be addressed. */ + @NonNull ERROR("Error"), /** * Warning: Probably a problem. */ + @NonNull WARNING("Warning"), /** * Information only: Might not be a problem, but the check has found * something interesting to say about the code. */ + @NonNull INFORMATIONAL("Information"), /** * Ignore: The user doesn't want to see this issue */ + @NonNull IGNORE("Ignore"); - private String mDisplay; + @NonNull + private final String mDisplay; private Severity(@NonNull String display) { mDisplay = display; @@ -65,8 +71,7 @@ public enum Severity { * * @return a description of the severity */ - @NonNull - public String getDescription() { + public @NonNull String getDescription() { return mDisplay; } }
\ No newline at end of file diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/AccessibilityDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/AccessibilityDetector.java index abc08b2..323f88a 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/AccessibilityDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/AccessibilityDetector.java @@ -21,6 +21,7 @@ import static com.android.tools.lint.detector.api.LintConstants.ATTR_CONTENT_DES import static com.android.tools.lint.detector.api.LintConstants.IMAGE_BUTTON; import static com.android.tools.lint.detector.api.LintConstants.IMAGE_VIEW; +import com.android.annotations.NonNull; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Issue; import com.android.tools.lint.detector.api.LayoutDetector; @@ -62,7 +63,7 @@ public class AccessibilityDetector extends LayoutDetector { } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @@ -75,7 +76,7 @@ public class AccessibilityDetector extends LayoutDetector { } @Override - public void visitElement(XmlContext context, Element element) { + public void visitElement(@NonNull XmlContext context, @NonNull Element element) { if (!element.hasAttributeNS(ANDROID_URI, ATTR_CONTENT_DESCRIPTION)) { context.report(ISSUE, element, context.getLocation(element), "[Accessibility] Missing contentDescription attribute on image", null); diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/AlwaysShowActionDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/AlwaysShowActionDetector.java index 9bbb4c1..bc5eaae 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/AlwaysShowActionDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/AlwaysShowActionDetector.java @@ -98,7 +98,7 @@ public class AlwaysShowActionDetector extends ResourceXmlDetector implements Jav } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @@ -108,12 +108,12 @@ public class AlwaysShowActionDetector extends ResourceXmlDetector implements Jav } @Override - public void beforeCheckFile(Context context) { + public void beforeCheckFile(@NonNull Context context) { mFileAttributes = null; } @Override - public void afterCheckFile(Context context) { + public void afterCheckFile(@NonNull Context context) { if (mFileAttributes != null) { assert context instanceof XmlContext; // mAFilettributes is only set in XML files @@ -161,7 +161,7 @@ public class AlwaysShowActionDetector extends ResourceXmlDetector implements Jav } @Override - public void afterCheckProject(Context context) { + public void afterCheckProject(@NonNull Context context) { if (mAlwaysFields != null && !mHasIfRoomRefs) { for (Location location : mAlwaysFields) { context.report(ISSUE, location, @@ -174,7 +174,7 @@ public class AlwaysShowActionDetector extends ResourceXmlDetector implements Jav // ---- Implements XmlScanner ---- @Override - public void visitAttribute(XmlContext context, Attr attribute) { + public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) { if (mFileAttributes == null) { mFileAttributes = new ArrayList<Attr>(); } @@ -190,7 +190,7 @@ public class AlwaysShowActionDetector extends ResourceXmlDetector implements Jav } @Override - public AstVisitor createJavaVisitor(JavaContext context) { + public AstVisitor createJavaVisitor(@NonNull JavaContext context) { return new FieldAccessChecker(context); } diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ApiDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ApiDetector.java index 43bd7a8..9eae7c4 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ApiDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ApiDetector.java @@ -17,6 +17,7 @@ package com.android.tools.lint.checks; import static com.android.tools.lint.detector.api.LintConstants.ANDROID_RESOURCE_PREFIX; +import static com.android.tools.lint.detector.api.LintConstants.CONSTRUCTOR_NAME; import static com.android.tools.lint.detector.api.LintConstants.TARGET_API; import com.android.annotations.NonNull; @@ -93,17 +94,17 @@ public class ApiDetector extends ResourceXmlDetector implements Detector.ClassSc } @Override - public boolean appliesTo(Context context, File file) { + public boolean appliesTo(@NonNull Context context, @NonNull File file) { return true; } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.SLOW; } @Override - public void beforeCheckProject(Context context) { + public void beforeCheckProject(@NonNull Context context) { mApiDatabase = ApiLookup.get(context.getClient()); // We can't look up the minimum API required by the project here: // The manifest file hasn't been processed yet in the -before- project hook. @@ -129,7 +130,7 @@ public class ApiDetector extends ResourceXmlDetector implements Detector.ClassSc } @Override - public void visitAttribute(XmlContext context, Attr attribute) { + public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) { if (mApiDatabase == null) { return; } @@ -157,7 +158,7 @@ public class ApiDetector extends ResourceXmlDetector implements Detector.ClassSc } @Override - public void visitElement(XmlContext context, Element element) { + public void visitElement(@NonNull XmlContext context, @NonNull Element element) { if (mApiDatabase == null) { return; } @@ -205,7 +206,7 @@ public class ApiDetector extends ResourceXmlDetector implements Detector.ClassSc } // TODO: Consider other widgets outside of android.widget.* int api = mApiDatabase.getCallVersion("android/widget/" + tag, //$NON-NLS-1$ - "<init>", //$NON-NLS-1$ + CONSTRUCTOR_NAME, // Not all views provided this constructor right away, for example, // LinearLayout added it in API 11 yet LinearLayout is much older: // "(Landroid/content/Context;Landroid/util/AttributeSet;I)V"); //$NON-NLS-1$ @@ -233,7 +234,7 @@ public class ApiDetector extends ResourceXmlDetector implements Detector.ClassSc @SuppressWarnings("rawtypes") @Override - public void checkClass(final ClassContext context, ClassNode classNode) { + public void checkClass(final @NonNull ClassContext context, @NonNull ClassNode classNode) { if (mApiDatabase == null) { return; } @@ -318,7 +319,7 @@ public class ApiDetector extends ResourceXmlDetector implements Detector.ClassSc owner = classNode.superName; } - do { + while (owner != null) { int api = mApiDatabase.getCallVersion(owner, name, desc); if (api > minSdk) { String fqcn = owner.replace('/', '.') + '#' + name; @@ -338,7 +339,7 @@ public class ApiDetector extends ResourceXmlDetector implements Detector.ClassSc } else { owner = null; } - } while (owner != null); + } } else if (type == AbstractInsnNode.FIELD_INSN) { FieldInsnNode node = (FieldInsnNode) instruction; String name = node.name; @@ -463,7 +464,7 @@ public class ApiDetector extends ResourceXmlDetector implements Detector.ClassSc // If looking for a constructor, the string we'll see in the source is not the // method name (<init>) but the class name - if (patternStart != null && patternStart.equals("<init>") //$NON-NLS-1$ + if (patternStart != null && patternStart.equals(CONSTRUCTOR_NAME) && node instanceof MethodInsnNode) { String owner = ((MethodInsnNode) node).owner; patternStart = owner.substring(owner.lastIndexOf('/') + 1); diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ApiLookup.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ApiLookup.java index dd5585b..4186028 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ApiLookup.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ApiLookup.java @@ -739,7 +739,7 @@ public class ApiLookup { return -1; } - private int findMember(int classNumber, @NonNull String name, @NonNull String desc) { + private int findMember(int classNumber, @NonNull String name, @Nullable String desc) { // The index array contains class indexes from 0 to classCount and // member indices from classCount to mIndices.length. int low = mClassCount; diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ArraySizeDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ArraySizeDetector.java index 568e885..92743b8 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ArraySizeDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ArraySizeDetector.java @@ -22,6 +22,7 @@ import static com.android.tools.lint.detector.api.LintConstants.TAG_ARRAY; import static com.android.tools.lint.detector.api.LintConstants.TAG_INTEGER_ARRAY; import static com.android.tools.lint.detector.api.LintConstants.TAG_STRING_ARRAY; +import com.android.annotations.NonNull; import com.android.resources.ResourceFolderType; import com.android.tools.lint.client.api.LintDriver; import com.android.tools.lint.detector.api.Category; @@ -32,7 +33,6 @@ 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 com.android.util.Pair; @@ -91,16 +91,11 @@ public class ArraySizeDetector extends ResourceXmlDetector { } @Override - public boolean appliesTo(ResourceFolderType folderType) { + public boolean appliesTo(@NonNull ResourceFolderType folderType) { return folderType == ResourceFolderType.VALUES; } @Override - public Speed getSpeed() { - return Speed.NORMAL; - } - - @Override public Collection<String> getApplicableElements() { return Arrays.asList( TAG_ARRAY, @@ -110,14 +105,14 @@ public class ArraySizeDetector extends ResourceXmlDetector { } @Override - public void beforeCheckProject(Context context) { + public void beforeCheckProject(@NonNull Context context) { if (context.getPhase() == 1) { mFileToArrayCount = new HashMap<File, Pair<String,Integer>>(30); } } @Override - public void afterCheckProject(Context context) { + public void afterCheckProject(@NonNull Context context) { if (context.getPhase() == 1) { // Check that all arrays for the same name have the same number of translations @@ -222,7 +217,7 @@ public class ArraySizeDetector extends ResourceXmlDetector { } @Override - public void visitElement(XmlContext context, Element element) { + public void visitElement(@NonNull XmlContext context, @NonNull Element element) { int phase = context.getPhase(); Attr attribute = element.getAttributeNode(ATTR_NAME); diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/BuiltinIssueRegistry.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/BuiltinIssueRegistry.java index 720c0da..146da7f 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/BuiltinIssueRegistry.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/BuiltinIssueRegistry.java @@ -19,6 +19,7 @@ package com.android.tools.lint.checks; import static com.android.tools.lint.detector.api.LintUtils.assertionsEnabled; import static com.android.tools.lint.detector.api.LintUtils.endsWith; +import com.android.annotations.NonNull; import com.android.prefs.AndroidLocation; import com.android.prefs.AndroidLocation.AndroidLocationException; import com.android.tools.lint.client.api.IssueRegistry; @@ -53,7 +54,7 @@ public class BuiltinIssueRegistry extends IssueRegistry { private static final List<Issue> sIssues; static { - final int initialCapacity = 91; + final int initialCapacity = 92; List<Issue> issues = new ArrayList<Issue>(initialCapacity); issues.add(AccessibilityDetector.ISSUE); @@ -86,6 +87,7 @@ public class BuiltinIssueRegistry extends IssueRegistry { issues.add(OnClickDetector.ISSUE); issues.add(RegistrationDetector.ISSUE); issues.add(HandlerDetector.ISSUE); + issues.add(FragmentDetector.ISSUE); issues.add(TranslationDetector.EXTRA); issues.add(TranslationDetector.MISSING); issues.add(HardcodedValuesDetector.ISSUE); @@ -172,7 +174,7 @@ public class BuiltinIssueRegistry extends IssueRegistry { } @Override - public List<Issue> getIssues() { + public @NonNull List<Issue> getIssues() { return sIssues; } diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ButtonDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ButtonDetector.java index 9321561..b644b14 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ButtonDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ButtonDetector.java @@ -178,7 +178,7 @@ public class ButtonDetector extends ResourceXmlDetector { } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @@ -193,7 +193,7 @@ public class ButtonDetector extends ResourceXmlDetector { } @Override - public void afterCheckProject(Context context) { + 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 @@ -214,7 +214,7 @@ public class ButtonDetector extends ResourceXmlDetector { } @Override - public void visitElement(XmlContext context, Element element) { + 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. diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ChildCountDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ChildCountDetector.java index 5a14f75..2f4503b 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ChildCountDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ChildCountDetector.java @@ -22,6 +22,7 @@ import static com.android.tools.lint.detector.api.LintConstants.LIST_VIEW; import static com.android.tools.lint.detector.api.LintConstants.REQUEST_FOCUS; import static com.android.tools.lint.detector.api.LintConstants.SCROLL_VIEW; +import com.android.annotations.NonNull; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Issue; import com.android.tools.lint.detector.api.LayoutDetector; @@ -74,7 +75,7 @@ public class ChildCountDetector extends LayoutDetector { } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @@ -90,7 +91,7 @@ public class ChildCountDetector extends LayoutDetector { } @Override - public void visitElement(XmlContext context, Element element) { + public void visitElement(@NonNull XmlContext context, @NonNull Element element) { int childCount = LintUtils.getChildCount(element); String tagName = element.getTagName(); if (tagName.equals(SCROLL_VIEW) || tagName.equals(HORIZONTAL_SCROLL_VIEW)) { diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ColorUsageDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ColorUsageDetector.java index e6d077a..dc3410b 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ColorUsageDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ColorUsageDetector.java @@ -18,6 +18,8 @@ package com.android.tools.lint.checks; import static com.android.tools.lint.detector.api.LintConstants.RESOURCE_CLZ_COLOR; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Context; import com.android.tools.lint.detector.api.Detector; @@ -60,12 +62,12 @@ public class ColorUsageDetector extends Detector implements Detector.JavaScanner } @Override - public boolean appliesTo(Context context, File file) { + public boolean appliesTo(@NonNull Context context, @NonNull File file) { return true; } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @@ -77,8 +79,8 @@ public class ColorUsageDetector extends Detector implements Detector.JavaScanner } @Override - public void visitResourceReference(JavaContext context, AstVisitor visitor, - Node select, String type, String name, boolean isFramework) { + public void visitResourceReference(@NonNull JavaContext context, @Nullable AstVisitor visitor, + @NonNull Node select, @NonNull String type, @NonNull String name, boolean isFramework) { if (type.equals(RESOURCE_CLZ_COLOR)) { while (select.getParent() instanceof Select) { select = select.getParent(); diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/DeprecationDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/DeprecationDetector.java index 25c247d..952224c 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/DeprecationDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/DeprecationDetector.java @@ -28,6 +28,7 @@ import static com.android.tools.lint.detector.api.LintConstants.ATTR_PASSWORD; import static com.android.tools.lint.detector.api.LintConstants.ATTR_PHONE_NUMBER; import static com.android.tools.lint.detector.api.LintConstants.ATTR_SINGLE_LINE; +import com.android.annotations.NonNull; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Issue; import com.android.tools.lint.detector.api.LayoutDetector; @@ -64,7 +65,7 @@ public class DeprecationDetector extends LayoutDetector { } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @@ -119,13 +120,13 @@ public class DeprecationDetector extends LayoutDetector { } @Override - public void visitElement(XmlContext context, Element element) { + public void visitElement(@NonNull XmlContext context, @NonNull Element element) { context.report(ISSUE, element, context.getLocation(element), String.format("%1$s is deprecated", element.getTagName()), null); } @Override - public void visitAttribute(XmlContext context, Attr attribute) { + public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) { if (!ANDROID_URI.equals(attribute.getNamespaceURI())) { return; } diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/DetectMissingPrefix.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/DetectMissingPrefix.java index 6ea7899..8a9c0a9 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/DetectMissingPrefix.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/DetectMissingPrefix.java @@ -23,6 +23,7 @@ import static com.android.tools.lint.detector.api.LintConstants.ATTR_STYLE; import static com.android.tools.lint.detector.api.LintConstants.VIEW_TAG; import static com.android.tools.lint.detector.api.LintConstants.XMLNS_PREFIX; +import com.android.annotations.NonNull; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Issue; import com.android.tools.lint.detector.api.LayoutDetector; @@ -70,7 +71,7 @@ public class DetectMissingPrefix extends LayoutDetector { } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @@ -80,7 +81,7 @@ public class DetectMissingPrefix extends LayoutDetector { } @Override - public void visitAttribute(XmlContext context, Attr attribute) { + public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) { String uri = attribute.getNamespaceURI(); if (uri == null || uri.length() == 0) { String name = attribute.getName(); diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/DuplicateIdDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/DuplicateIdDetector.java index bbb3de5..c8e34c5 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/DuplicateIdDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/DuplicateIdDetector.java @@ -24,6 +24,7 @@ import static com.android.tools.lint.detector.api.LintConstants.INCLUDE; import static com.android.tools.lint.detector.api.LintConstants.LAYOUT_RESOURCE_PREFIX; import static com.android.tools.lint.detector.api.LintConstants.NEW_ID_RESOURCE_PREFIX; +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; @@ -103,12 +104,12 @@ public class DuplicateIdDetector extends LayoutDetector { @Override - public boolean appliesTo(ResourceFolderType folderType) { + public boolean appliesTo(@NonNull ResourceFolderType folderType) { return folderType == ResourceFolderType.LAYOUT || folderType == ResourceFolderType.MENU; } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @@ -123,14 +124,14 @@ public class DuplicateIdDetector extends LayoutDetector { } @Override - public void beforeCheckFile(Context context) { + public void beforeCheckFile(@NonNull Context context) { if (context.getPhase() == 1) { mIds = new HashSet<String>(); } } @Override - public void afterCheckFile(Context context) { + public void afterCheckFile(@NonNull Context context) { if (context.getPhase() == 1) { // Store this layout's set of ids for full project analysis in afterCheckProject mFileToIds.put(context.file, mIds); @@ -140,7 +141,7 @@ public class DuplicateIdDetector extends LayoutDetector { } @Override - public void beforeCheckProject(Context context) { + public void beforeCheckProject(@NonNull Context context) { if (context.getPhase() == 1) { mFileToIds = new HashMap<File, Set<String>>(); mIncludes = new HashMap<File, List<String>>(); @@ -148,7 +149,7 @@ public class DuplicateIdDetector extends LayoutDetector { } @Override - public void afterCheckProject(Context context) { + public void afterCheckProject(@NonNull Context context) { if (context.getPhase() == 1) { // Look for duplicates if (mIncludes.size() > 0) { @@ -201,7 +202,7 @@ public class DuplicateIdDetector extends LayoutDetector { } @Override - public void visitElement(XmlContext context, Element element) { + public void visitElement(@NonNull XmlContext context, @NonNull Element element) { // Record include graph such that we can look for inter-layout duplicates after the // project has been fully checked @@ -241,7 +242,7 @@ public class DuplicateIdDetector extends LayoutDetector { } @Override - public void visitAttribute(XmlContext context, Attr attribute) { + public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) { assert attribute.getName().equals(ATTR_ID) || attribute.getLocalName().equals(ATTR_ID); String id = attribute.getValue(); if (context.getPhase() == 1) { diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ExtraTextDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ExtraTextDetector.java index e0665df..7e2ecb2 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ExtraTextDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ExtraTextDetector.java @@ -16,6 +16,7 @@ package com.android.tools.lint.checks; +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.DefaultPosition; @@ -59,7 +60,7 @@ public class ExtraTextDetector extends ResourceXmlDetector { } @Override - public boolean appliesTo(ResourceFolderType folderType) { + public boolean appliesTo(@NonNull ResourceFolderType folderType) { return folderType == ResourceFolderType.LAYOUT || folderType == ResourceFolderType.MENU || folderType == ResourceFolderType.ANIMATOR @@ -69,12 +70,12 @@ public class ExtraTextDetector extends ResourceXmlDetector { } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @Override - public void visitDocument(XmlContext context, Document document) { + public void visitDocument(@NonNull XmlContext context, @NonNull Document document) { mFoundText = false; visitNode(context, document); } diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/FieldGetterDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/FieldGetterDetector.java index 656c226..7d8deab 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/FieldGetterDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/FieldGetterDetector.java @@ -16,6 +16,7 @@ package com.android.tools.lint.checks; +import com.android.annotations.NonNull; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.ClassContext; import com.android.tools.lint.detector.api.Context; @@ -72,12 +73,12 @@ public class FieldGetterDetector extends Detector implements Detector.ClassScann } @Override - public boolean appliesTo(Context context, File file) { + public boolean appliesTo(@NonNull Context context, @NonNull File file) { return true; } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @@ -85,7 +86,7 @@ public class FieldGetterDetector extends Detector implements Detector.ClassScann @SuppressWarnings("rawtypes") @Override - public void checkClass(ClassContext context, ClassNode classNode) { + public void checkClass(@NonNull ClassContext context, @NonNull ClassNode classNode) { List<Entry> pendingCalls = null; int currentLine = 0; List methodList = classNode.methods; diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/FragmentDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/FragmentDetector.java new file mode 100644 index 0000000..6839004 --- /dev/null +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/FragmentDetector.java @@ -0,0 +1,169 @@ +/* + * 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.tools.lint.detector.api.LintConstants.CONSTRUCTOR_NAME; +import static com.android.tools.lint.detector.api.LintConstants.FRAGMENT; +import static com.android.tools.lint.detector.api.LintConstants.FRAGMENT_V4; + +import com.android.annotations.NonNull; +import com.android.tools.lint.client.api.LintDriver; +import com.android.tools.lint.detector.api.Category; +import com.android.tools.lint.detector.api.ClassContext; +import com.android.tools.lint.detector.api.Context; +import com.android.tools.lint.detector.api.Detector; +import com.android.tools.lint.detector.api.Detector.ClassScanner; +import com.android.tools.lint.detector.api.Issue; +import com.android.tools.lint.detector.api.LintUtils; +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 org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.MethodNode; + +import java.io.File; +import java.util.List; + +/** + * Checks that Fragment subclasses can be instantiated via + * {link {@link Class#newInstance()}}: the class is public, static, and has + * a public null constructor. + * <p> + * This helps track down issues like + * http://stackoverflow.com/questions/8058809/fragment-activity-crashes-on-screen-rotate + * (and countless duplicates) + */ +public class FragmentDetector extends Detector implements ClassScanner { + private static final String FRAGMENT_NAME_SUFFIX = "Fragment"; //$NON-NLS-1$ + + /** Are fragment subclasses instantiatable? */ + public static final Issue ISSUE = Issue.create( + "ValidFragment", //$NON-NLS-1$ + "Ensures that Fragment subclasses can be instantiated", + + "From the Fragment documentation:\n" + + "*Every* fragment must have an empty constructor, so it can be instantiated when " + + "restoring its activity's state. It is strongly recommended that subclasses do not " + + "have other constructors with parameters, since these constructors will not be " + + "called when the fragment is re-instantiated; instead, arguments can be supplied " + + "by the caller with setArguments(Bundle) and later retrieved by the Fragment " + + "with getArguments().", + + Category.CORRECTNESS, + 6, + Severity.WARNING, + FragmentDetector.class, + Scope.CLASS_FILE_SCOPE).setMoreInfo( + "http://developer.android.com/reference/android/app/Fragment.html#Fragment()"); //$NON-NLS-1$ + + + /** Constructs a new {@link FragmentDetector} */ + public FragmentDetector() { + } + + @Override + public @NonNull Speed getSpeed() { + return Speed.FAST; + } + + @Override + public boolean appliesTo(@NonNull Context context, @NonNull File file) { + return true; + } + + // ---- Implements ClassScanner ---- + + @Override + public void checkClass(@NonNull ClassContext context, @NonNull ClassNode classNode) { + if ((classNode.access & Opcodes.ACC_ABSTRACT) != 0) { + // Ignore abstract classes since they are clearly (and by definition) not intended to + // be instantiated. We're looking for accidental non-static or missing constructor + // scenarios here. + return; + } + + LintDriver driver = context.getDriver(); + + if (!(driver.isSubclassOf(classNode, FRAGMENT) + || driver.isSubclassOf(classNode, FRAGMENT_V4))) { + if (!context.getScope().contains(Scope.ALL_JAVA_FILES)) { + // Single file checking: Just check that it looks like a fragment class + // (since we don't have a full superclass map) + if (!classNode.name.endsWith(FRAGMENT_NAME_SUFFIX) || + classNode.superName == null) { + return; + } + } else { + return; + } + } + + if ((classNode.access & Opcodes.ACC_PUBLIC) == 0) { + context.report(ISSUE, context.getLocation(classNode), String.format( + "This fragment class should be public (%1$s)", + ClassContext.createSignature(classNode.name, null, null)), + null); + return; + } + + if (classNode.name.indexOf('$') != -1 && !LintUtils.isStaticInnerClass(classNode)) { + context.report(ISSUE, context.getLocation(classNode), String.format( + "This fragment inner class should be static (%1$s)", + ClassContext.createSignature(classNode.name, null, null)), + null); + return; + } + + boolean hasDefaultConstructor = false; + @SuppressWarnings("rawtypes") // ASM API + List methodList = classNode.methods; + for (Object m : methodList) { + MethodNode method = (MethodNode) m; + if (method.name.equals(CONSTRUCTOR_NAME)) { + if (method.desc.equals("()V")) { //$NON-NLS-1$ + // The constructor must be public + if ((method.access & Opcodes.ACC_PUBLIC) != 0) { + hasDefaultConstructor = true; + } else { + context.report(ISSUE, context.getLocation(method, classNode), + "The default constructor must be public", + null); + // Also mark that we have a constructor so we don't complain again + // below since we've already emitted a more specific error related + // to the default constructor + hasDefaultConstructor = true; + } + } else if (!method.desc.contains("()")) { //$NON-NLS-1$ + context.report(ISSUE, context.getLocation(method, classNode), + "Avoid non-default constructors in fragments: use a default constructor " + + "plus Fragment#setArguments(Bundle) instead", + null); + } + } + } + + if (!hasDefaultConstructor) { + context.report(ISSUE, context.getLocation(classNode), String.format( + "This fragment should provide a default constructor (a public " + + "constructor with no arguments) (%1$s)", + ClassContext.createSignature(classNode.name, null, null)), + null); + } + } +} diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/GridLayoutDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/GridLayoutDetector.java index 762a4b5..6e8d8a3 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/GridLayoutDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/GridLayoutDetector.java @@ -22,6 +22,7 @@ import static com.android.tools.lint.detector.api.LintConstants.ATTR_LAYOUT_COLU import static com.android.tools.lint.detector.api.LintConstants.ATTR_LAYOUT_ROW; import static com.android.tools.lint.detector.api.LintConstants.ATTR_ROW_COUNT; +import com.android.annotations.NonNull; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Issue; import com.android.tools.lint.detector.api.LayoutDetector; @@ -60,7 +61,7 @@ public class GridLayoutDetector extends LayoutDetector { } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @@ -85,7 +86,7 @@ public class GridLayoutDetector extends LayoutDetector { } @Override - public void visitElement(XmlContext context, Element element) { + public void visitElement(@NonNull XmlContext context, @NonNull Element element) { int declaredRowCount = getInt(element, ATTR_ROW_COUNT, -1); int declaredColumnCount = getInt(element, ATTR_COLUMN_COUNT, -1); diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/HandlerDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/HandlerDetector.java index 03a611f..9efd666 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/HandlerDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/HandlerDetector.java @@ -17,25 +17,21 @@ package com.android.tools.lint.checks; import com.android.annotations.NonNull; -import com.android.tools.lint.client.api.LintDriver; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.ClassContext; import com.android.tools.lint.detector.api.Context; import com.android.tools.lint.detector.api.Detector; import com.android.tools.lint.detector.api.Detector.ClassScanner; 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.Scope; import com.android.tools.lint.detector.api.Severity; import com.android.tools.lint.detector.api.Speed; -import org.objectweb.asm.Opcodes; import org.objectweb.asm.tree.ClassNode; -import org.objectweb.asm.tree.FieldNode; import java.io.File; -import java.util.EnumSet; -import java.util.List; /** * Checks that Handler implementations are top level classes or static. @@ -58,64 +54,37 @@ public class HandlerDetector extends Detector implements ClassScanner { 4, Severity.WARNING, HandlerDetector.class, - EnumSet.of(Scope.CLASS_FILE)); + Scope.CLASS_FILE_SCOPE); /** Constructs a new {@link HandlerDetector} */ public HandlerDetector() { } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @Override - public boolean appliesTo(Context context, File file) { + public boolean appliesTo(@NonNull Context context, @NonNull File file) { return true; } // ---- Implements ClassScanner ---- @Override - public void checkClass(ClassContext context, ClassNode classNode) { + public void checkClass(@NonNull ClassContext context, @NonNull ClassNode classNode) { if (classNode.name.indexOf('$') == -1) { return; } - // Note: We can't just filter out static inner classes like this: - // (classNode.access & Opcodes.ACC_STATIC) != 0 - // because the static flag only appears on methods and fields in the class - // file. Instead, look for the synthetic this pointer. - - LintDriver driver = context.getDriver(); - String name = classNode.name; - while (name != null) { - if (name.equals("android/os/Handler")) { //$NON-NLS-1$ - if (isStaticInnerClass(classNode)) { - return; - } - - Location location = context.getLocation(classNode); - context.report(ISSUE, location, String.format( - "This Handler class should be static or leaks might occur (%1$s)", - ClassContext.createSignature(classNode.name, null, null)), - null); - return; - } - name = driver.getSuperClass(name); + if (context.getDriver().isSubclassOf(classNode, "android/os/Handler") //$NON-NLS-1$ + && !LintUtils.isStaticInnerClass(classNode)) { + Location location = context.getLocation(classNode); + context.report(ISSUE, location, String.format( + "This Handler class should be static or leaks might occur (%1$s)", + ClassContext.createSignature(classNode.name, null, null)), + null); } } - - private boolean isStaticInnerClass(@NonNull ClassNode classNode) { - @SuppressWarnings("rawtypes") // ASM API - List fieldList = classNode.fields; - for (Object f : fieldList) { - FieldNode field = (FieldNode) f; - if (field.name.startsWith("this$") && (field.access & Opcodes.ACC_SYNTHETIC) != 0) { - return false; - } - } - - return true; - } } diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/HardcodedDebugModeDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/HardcodedDebugModeDetector.java index df8c728..1237e1b 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/HardcodedDebugModeDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/HardcodedDebugModeDetector.java @@ -20,6 +20,7 @@ import static com.android.tools.lint.detector.api.LintConstants.ANDROID_MANIFEST import static com.android.tools.lint.detector.api.LintConstants.ANDROID_URI; import static com.android.tools.lint.detector.api.LintConstants.ATTR_DEBUGGABLE; +import com.android.annotations.NonNull; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Context; import com.android.tools.lint.detector.api.Detector; @@ -65,12 +66,12 @@ public class HardcodedDebugModeDetector extends Detector implements Detector.Xml } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @Override - public boolean appliesTo(Context context, File file) { + public boolean appliesTo(@NonNull Context context, @NonNull File file) { return file.getName().equals(ANDROID_MANIFEST_XML); } @@ -82,7 +83,7 @@ public class HardcodedDebugModeDetector extends Detector implements Detector.Xml } @Override - public void visitAttribute(XmlContext context, Attr attribute) { + public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) { if (attribute.getNamespaceURI().equals(ANDROID_URI)) { //if (attribute.getOwnerElement().getTagName().equals(TAG_APPLICATION)) { context.report(ISSUE, attribute, context.getLocation(attribute), diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/HardcodedValuesDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/HardcodedValuesDetector.java index 09a3ffc..3665303 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/HardcodedValuesDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/HardcodedValuesDetector.java @@ -23,6 +23,7 @@ import static com.android.tools.lint.detector.api.LintConstants.ATTR_LABEL; import static com.android.tools.lint.detector.api.LintConstants.ATTR_PROMPT; import static com.android.tools.lint.detector.api.LintConstants.ATTR_TEXT; +import com.android.annotations.NonNull; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Issue; import com.android.tools.lint.detector.api.LayoutDetector; @@ -66,7 +67,7 @@ public class HardcodedValuesDetector extends LayoutDetector { } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @@ -82,7 +83,7 @@ public class HardcodedValuesDetector extends LayoutDetector { } @Override - public void visitAttribute(XmlContext context, Attr attribute) { + public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) { String value = attribute.getValue(); if (value.length() > 0 && (value.charAt(0) != '@' && value.charAt(0) != '?')) { // Make sure this is really one of the android: attributes diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/IconDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/IconDetector.java index c687d74..adee77d 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/IconDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/IconDetector.java @@ -34,6 +34,7 @@ import static com.android.tools.lint.detector.api.LintConstants.RES_FOLDER; import static com.android.tools.lint.detector.api.LintConstants.TAG_APPLICATION; import static com.android.tools.lint.detector.api.LintUtils.endsWith; +import com.android.annotations.NonNull; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Context; import com.android.tools.lint.detector.api.Detector; @@ -258,22 +259,22 @@ public class IconDetector extends Detector implements Detector.XmlScanner { } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.SLOW; } @Override - public void beforeCheckProject(Context context) { + public void beforeCheckProject(@NonNull Context context) { mApplicationIcon = null; } @Override - public void afterCheckLibraryProject(Context context) { + public void afterCheckLibraryProject(@NonNull Context context) { checkResourceFolder(context, context.getProject().getDir()); } @Override - public void afterCheckProject(Context context) { + public void afterCheckProject(@NonNull Context context) { checkResourceFolder(context, context.getProject().getDir()); } @@ -1203,7 +1204,7 @@ public class IconDetector extends Detector implements Detector.XmlScanner { // XML detector: Skim manifest @Override - public boolean appliesTo(Context context, File file) { + public boolean appliesTo(@NonNull Context context, @NonNull File file) { return file.getName().equals(ANDROID_MANIFEST_XML); } @@ -1213,7 +1214,7 @@ public class IconDetector extends Detector implements Detector.XmlScanner { } @Override - public void visitElement(XmlContext context, Element element) { + public void visitElement(@NonNull XmlContext context, @NonNull Element element) { assert element.getTagName().equals(TAG_APPLICATION); mApplicationIcon = element.getAttributeNS(ANDROID_URI, ATTR_ICON); if (mApplicationIcon.startsWith(DRAWABLE_RESOURCE_PREFIX)) { diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/InefficientWeightDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/InefficientWeightDetector.java index 84216d1..3fd5573 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/InefficientWeightDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/InefficientWeightDetector.java @@ -25,6 +25,7 @@ import static com.android.tools.lint.detector.api.LintConstants.ATTR_ORIENTATION import static com.android.tools.lint.detector.api.LintConstants.LINEAR_LAYOUT; import static com.android.tools.lint.detector.api.LintConstants.VALUE_VERTICAL; +import com.android.annotations.NonNull; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Issue; import com.android.tools.lint.detector.api.LayoutDetector; @@ -100,7 +101,7 @@ public class InefficientWeightDetector extends LayoutDetector { } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @@ -110,7 +111,7 @@ public class InefficientWeightDetector extends LayoutDetector { } @Override - public void visitElement(XmlContext context, Element element) { + public void visitElement(@NonNull XmlContext context, @NonNull Element element) { List<Element> children = LintUtils.getChildren(element); // See if there is exactly one child with a weight boolean multipleWeights = false; diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/JavaPerformanceDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/JavaPerformanceDetector.java index e99005c..0073d06 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/JavaPerformanceDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/JavaPerformanceDetector.java @@ -16,6 +16,7 @@ package com.android.tools.lint.checks; +import com.android.annotations.NonNull; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Context; import com.android.tools.lint.detector.api.Detector; @@ -139,12 +140,12 @@ public class JavaPerformanceDetector extends Detector implements Detector.JavaSc } @Override - public boolean appliesTo(Context context, File file) { + public boolean appliesTo(@NonNull Context context, @NonNull File file) { return true; } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @@ -160,7 +161,7 @@ public class JavaPerformanceDetector extends Detector implements Detector.JavaSc } @Override - public AstVisitor createJavaVisitor(JavaContext context) { + public AstVisitor createJavaVisitor(@NonNull JavaContext context) { return new PerformanceVisitor(context); } diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ManifestOrderDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ManifestOrderDetector.java index cf75ae5..b116eb9 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ManifestOrderDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ManifestOrderDetector.java @@ -31,6 +31,7 @@ import static com.android.tools.lint.detector.api.LintConstants.TAG_USES_LIBRARY import static com.android.tools.lint.detector.api.LintConstants.TAG_USES_PERMISSION; import static com.android.tools.lint.detector.api.LintConstants.TAG_USES_SDK; +import com.android.annotations.NonNull; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Context; import com.android.tools.lint.detector.api.Detector; @@ -159,23 +160,23 @@ public class ManifestOrderDetector extends Detector implements Detector.XmlScann private String mPackage; @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @Override - public boolean appliesTo(Context context, File file) { + public boolean appliesTo(@NonNull Context context, @NonNull File file) { return file.getName().equals(ANDROID_MANIFEST_XML); } @Override - public void beforeCheckFile(Context context) { + public void beforeCheckFile(@NonNull Context context) { mSeenApplication = false; mSeenUsesSdk = 0; } @Override - public void afterCheckFile(Context context) { + public void afterCheckFile(@NonNull Context context) { if (mSeenUsesSdk == 0 && context.isEnabled(USES_SDK)) { context.report(USES_SDK, Location.create(context.file), "Manifest should specify a minimum API level with " + @@ -209,7 +210,7 @@ public class ManifestOrderDetector extends Detector implements Detector.XmlScann } @Override - public void visitElement(XmlContext context, Element element) { + public void visitElement(@NonNull XmlContext context, @NonNull Element element) { String tag = element.getTagName(); Node parentNode = element.getParentNode(); diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/MathDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/MathDetector.java index 06258dd..daefda7 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/MathDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/MathDetector.java @@ -16,6 +16,7 @@ package com.android.tools.lint.checks; +import com.android.annotations.NonNull; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.ClassContext; import com.android.tools.lint.detector.api.Context; @@ -68,12 +69,12 @@ public class MathDetector extends Detector implements Detector.ClassScanner { } @Override - public boolean appliesTo(Context context, File file) { + public boolean appliesTo(@NonNull Context context, @NonNull File file) { return true; } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @@ -81,7 +82,7 @@ public class MathDetector extends Detector implements Detector.ClassScanner { @SuppressWarnings("rawtypes") @Override - public void checkClass(ClassContext context, ClassNode classNode) { + public void checkClass(@NonNull ClassContext context, @NonNull ClassNode classNode) { List methodList = classNode.methods; for (Object m : methodList) { MethodNode method = (MethodNode) m; diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/MergeRootFrameLayoutDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/MergeRootFrameLayoutDetector.java index 4cb96b5..5ed0257 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/MergeRootFrameLayoutDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/MergeRootFrameLayoutDetector.java @@ -103,17 +103,18 @@ public class MergeRootFrameLayoutDetector extends LayoutDetector implements Dete } @Override + @NonNull public Speed getSpeed() { return Speed.FAST; } @Override - public boolean appliesTo(Context context, File file) { + public boolean appliesTo(@NonNull Context context, @NonNull File file) { return LintUtils.isXmlFile(file) || LintUtils.endsWith(file.getName(), DOT_JAVA); } @Override - public void afterCheckProject(Context context) { + public void afterCheckProject(@NonNull Context context) { if (mPending != null && mWhitelistedLayouts != null) { // Process all the root FrameLayouts that are eligible, and generate // suggestions for <merge> replacements for any layouts that are included @@ -146,7 +147,7 @@ public class MergeRootFrameLayoutDetector extends LayoutDetector implements Dete } @Override - public void visitElement(XmlContext context, Element element) { + public void visitElement(@NonNull XmlContext context, @NonNull Element element) { String tag = element.getTagName(); if (tag.equals(INCLUDE)) { String layout = element.getAttribute(ATTR_LAYOUT); // NOTE: Not in android: namespace diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/NamespaceDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/NamespaceDetector.java index 88a9dd5..e760a9c 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/NamespaceDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/NamespaceDetector.java @@ -22,6 +22,7 @@ import static com.android.tools.lint.detector.api.LintConstants.AUTO_URI; import static com.android.tools.lint.detector.api.LintConstants.URI_PREFIX; import static com.android.tools.lint.detector.api.LintConstants.XMLNS_PREFIX; +import com.android.annotations.NonNull; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Issue; import com.android.tools.lint.detector.api.LayoutDetector; @@ -102,12 +103,12 @@ public class NamespaceDetector extends LayoutDetector { } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @Override - public void visitDocument(XmlContext context, Document document) { + public void visitDocument(@NonNull XmlContext context, @NonNull Document document) { boolean haveCustomNamespace = false; Element root = document.getDocumentElement(); NamedNodeMap attributes = root.getAttributes(); diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/NestedScrollingWidgetDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/NestedScrollingWidgetDetector.java index 9ca8017..d6cdbd6 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/NestedScrollingWidgetDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/NestedScrollingWidgetDetector.java @@ -22,6 +22,7 @@ import static com.android.tools.lint.detector.api.LintConstants.HORIZONTAL_SCROL import static com.android.tools.lint.detector.api.LintConstants.LIST_VIEW; import static com.android.tools.lint.detector.api.LintConstants.SCROLL_VIEW; +import com.android.annotations.NonNull; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Context; import com.android.tools.lint.detector.api.Issue; @@ -62,13 +63,13 @@ public class NestedScrollingWidgetDetector extends LayoutDetector { } @Override - public void beforeCheckFile(Context context) { + public void beforeCheckFile(@NonNull Context context) { mVisitingHorizontalScroll = 0; mVisitingVerticalScroll = 0; } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @@ -103,7 +104,7 @@ public class NestedScrollingWidgetDetector extends LayoutDetector { } @Override - public void visitElement(XmlContext context, Element element) { + public void visitElement(@NonNull XmlContext context, @NonNull Element element) { boolean vertical = isVerticalScroll(element); if (vertical) { mVisitingVerticalScroll++; @@ -129,7 +130,7 @@ public class NestedScrollingWidgetDetector extends LayoutDetector { } @Override - public void visitElementAfter(XmlContext context, Element element) { + public void visitElementAfter(@NonNull XmlContext context, @NonNull Element element) { if (isVerticalScroll(element)) { mVisitingVerticalScroll--; assert mVisitingVerticalScroll >= 0; diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ObsoleteLayoutParamsDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ObsoleteLayoutParamsDetector.java index 4002bd5..9972604 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ObsoleteLayoutParamsDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ObsoleteLayoutParamsDetector.java @@ -63,6 +63,7 @@ import static com.android.tools.lint.detector.api.LintConstants.RELATIVE_LAYOUT; import static com.android.tools.lint.detector.api.LintConstants.TABLE_ROW; import static com.android.tools.lint.detector.api.LintConstants.VIEW_TAG; +import com.android.annotations.NonNull; import com.android.tools.lint.client.api.IDomParser; import com.android.tools.lint.client.api.SdkInfo; import com.android.tools.lint.detector.api.Category; @@ -218,7 +219,7 @@ public class ObsoleteLayoutParamsDetector extends LayoutDetector { } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @@ -233,7 +234,7 @@ public class ObsoleteLayoutParamsDetector extends LayoutDetector { } @Override - public void visitAttribute(XmlContext context, Attr attribute) { + public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) { String name = attribute.getLocalName(); if (name != null && name.startsWith(ATTR_LAYOUT_PREFIX) && ANDROID_URI.equals(attribute.getNamespaceURI())) { @@ -296,7 +297,7 @@ public class ObsoleteLayoutParamsDetector extends LayoutDetector { } @Override - public void visitElement(XmlContext context, Element element) { + public void visitElement(@NonNull XmlContext context, @NonNull Element element) { String layout = element.getAttribute(ATTR_LAYOUT); if (layout.startsWith(LAYOUT_RESOURCE_PREFIX)) { // Ignore @android:layout/ layouts layout = layout.substring(LAYOUT_RESOURCE_PREFIX.length()); @@ -320,7 +321,7 @@ public class ObsoleteLayoutParamsDetector extends LayoutDetector { } @Override - public void afterCheckProject(Context context) { + public void afterCheckProject(@NonNull Context context) { if (mIncludes == null) { return; } diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/OnClickDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/OnClickDetector.java index 14370f3..75fda79 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/OnClickDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/OnClickDetector.java @@ -18,6 +18,7 @@ package com.android.tools.lint.checks; import static com.android.tools.lint.detector.api.LintConstants.ATTR_ON_CLICK; +import com.android.annotations.NonNull; import com.android.tools.lint.client.api.LintDriver; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.ClassContext; @@ -81,17 +82,17 @@ public class OnClickDetector extends LayoutDetector implements ClassScanner { } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @Override - public boolean appliesTo(Context context, File file) { + public boolean appliesTo(@NonNull Context context, @NonNull File file) { return true; } @Override - public void afterCheckProject(Context context) { + public void afterCheckProject(@NonNull Context context) { if (mNames != null && mNames.size() > 0 && mHaveBytecode) { List<String> names = new ArrayList<String>(mNames.keySet()); Collections.sort(names); @@ -129,7 +130,7 @@ public class OnClickDetector extends LayoutDetector implements ClassScanner { } @Override - public void visitAttribute(XmlContext context, Attr attribute) { + public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) { String value = attribute.getValue(); if (value.isEmpty() || value.trim().isEmpty()) { context.report(ISSUE, attribute, context.getLocation(attribute), @@ -170,7 +171,7 @@ public class OnClickDetector extends LayoutDetector implements ClassScanner { @SuppressWarnings("rawtypes") @Override - public void checkClass(ClassContext context, ClassNode classNode) { + public void checkClass(@NonNull ClassContext context, @NonNull ClassNode classNode) { if (mNames == null) { // No onClick attributes in the XML files return; diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/OverdrawDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/OverdrawDetector.java index 51790e5..12f9b04 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/OverdrawDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/OverdrawDetector.java @@ -35,6 +35,7 @@ import static com.android.tools.lint.detector.api.LintConstants.TRANSPARENT_COLO import static com.android.tools.lint.detector.api.LintConstants.VALUE_DISABLED; import static com.android.tools.lint.detector.api.LintUtils.endsWith; +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; @@ -148,7 +149,7 @@ public class OverdrawDetector extends LayoutDetector implements Detector.JavaSca } @Override - public boolean appliesTo(ResourceFolderType folderType) { + public boolean appliesTo(@NonNull ResourceFolderType folderType) { // Look in layouts for drawable resources return super.appliesTo(folderType) // and in resource files for theme definitions @@ -158,12 +159,12 @@ public class OverdrawDetector extends LayoutDetector implements Detector.JavaSca } @Override - public boolean appliesTo(Context context, File file) { + public boolean appliesTo(@NonNull Context context, @NonNull File file) { return LintUtils.isXmlFile(file) || LintUtils.endsWith(file.getName(), DOT_JAVA); } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @@ -194,7 +195,7 @@ public class OverdrawDetector extends LayoutDetector implements Detector.JavaSca } @Override - public void afterCheckProject(Context context) { + public void afterCheckProject(@NonNull Context context) { if (mRootAttributes != null) { for (Pair<Location, String> pair : mRootAttributes) { Location location = pair.getFirst(); @@ -260,7 +261,7 @@ public class OverdrawDetector extends LayoutDetector implements Detector.JavaSca // ---- Implements XmlScanner ---- @Override - public void visitAttribute(XmlContext context, Attr attribute) { + public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) { // Only consider the root element's background if (attribute.getOwnerDocument().getDocumentElement() == attribute.getOwnerElement()) { // If the drawable is a non-repeated pattern then the overdraw might be @@ -321,7 +322,7 @@ public class OverdrawDetector extends LayoutDetector implements Detector.JavaSca } @Override - public void beforeCheckFile(Context context) { + public void beforeCheckFile(@NonNull Context context) { if (endsWith(context.file.getName(), DOT_XML)) { // Drawable XML files should not be considered for overdraw, except for <bitmap>'s. // The bitmap elements are handled in the scanBitmap() method; it will clear @@ -339,7 +340,7 @@ public class OverdrawDetector extends LayoutDetector implements Detector.JavaSca } @Override - public void visitElement(XmlContext context, Element element) { + public void visitElement(@NonNull XmlContext context, @NonNull Element element) { String tag = element.getTagName(); if (tag.equals(TAG_STYLE)) { scanTheme(element); @@ -470,7 +471,7 @@ public class OverdrawDetector extends LayoutDetector implements Detector.JavaSca } @Override - public AstVisitor createJavaVisitor(JavaContext context) { + public AstVisitor createJavaVisitor(@NonNull JavaContext context) { return new OverdrawVisitor(); } diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/PrivateResourceDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/PrivateResourceDetector.java index 2b37f82..7d909ae 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/PrivateResourceDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/PrivateResourceDetector.java @@ -16,6 +16,7 @@ package com.android.tools.lint.checks; +import com.android.annotations.NonNull; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Issue; import com.android.tools.lint.detector.api.ResourceXmlDetector; @@ -52,7 +53,7 @@ public class PrivateResourceDetector extends ResourceXmlDetector { } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @@ -62,7 +63,7 @@ public class PrivateResourceDetector extends ResourceXmlDetector { } @Override - public void visitAttribute(XmlContext context, Attr attribute) { + public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) { String value = attribute.getNodeValue(); if (value.startsWith("@*android:")) { //$NON-NLS-1$ context.report(ISSUE, attribute, context.getLocation(attribute), diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ProguardDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ProguardDetector.java index c062507..41af3b1 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ProguardDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ProguardDetector.java @@ -19,6 +19,7 @@ package com.android.tools.lint.checks; import static com.android.tools.lint.detector.api.LintConstants.PROGUARD_CONFIG; import static com.android.tools.lint.detector.api.LintConstants.PROJECT_PROPERTIES; +import com.android.annotations.NonNull; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Context; import com.android.tools.lint.detector.api.Detector; @@ -91,7 +92,7 @@ public class ProguardDetector extends Detector { EnumSet.of(Scope.PROGUARD_FILE)); @Override - public void run(Context context) { + public void run(@NonNull Context context) { String contents = context.getContents(); if (contents != null) { if (context.isEnabled(WRONGKEEP)) { @@ -151,12 +152,12 @@ public class ProguardDetector extends Detector { } @Override - public boolean appliesTo(Context context, File file) { + public boolean appliesTo(@NonNull Context context, @NonNull File file) { return true; } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } } diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/PxUsageDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/PxUsageDetector.java index cb37d5f..f87abcc 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/PxUsageDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/PxUsageDetector.java @@ -16,6 +16,7 @@ package com.android.tools.lint.checks; +import com.android.annotations.NonNull; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Issue; import com.android.tools.lint.detector.api.LayoutDetector; @@ -59,7 +60,7 @@ public class PxUsageDetector extends LayoutDetector { } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @@ -69,7 +70,7 @@ public class PxUsageDetector extends LayoutDetector { } @Override - public void visitAttribute(XmlContext context, Attr attribute) { + public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) { String value = attribute.getValue(); if (value.endsWith("px") && value.matches("\\d+px")) { //$NON-NLS-1$ if (value.charAt(0) == '0') { diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/RegistrationDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/RegistrationDetector.java index 0f16244..1d55109 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/RegistrationDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/RegistrationDetector.java @@ -24,6 +24,7 @@ import static com.android.tools.lint.detector.api.LintConstants.TAG_PROVIDER; import static com.android.tools.lint.detector.api.LintConstants.TAG_RECEIVER; import static com.android.tools.lint.detector.api.LintConstants.TAG_SERVICE; +import com.android.annotations.NonNull; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.ClassContext; import com.android.tools.lint.detector.api.Context; @@ -85,12 +86,12 @@ public class RegistrationDetector extends LayoutDetector implements ClassScanner } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @Override - public boolean appliesTo(Context context, File file) { + public boolean appliesTo(@NonNull Context context, @NonNull File file) { return true; } @@ -102,7 +103,7 @@ public class RegistrationDetector extends LayoutDetector implements ClassScanner } @Override - public void visitElement(XmlContext context, Element element) { + public void visitElement(@NonNull XmlContext context, @NonNull Element element) { String fqcn = getFqcn(element); String tag = element.getTagName(); String frameworkClass = tagToClass(tag); @@ -148,7 +149,7 @@ public class RegistrationDetector extends LayoutDetector implements ClassScanner // ---- Implements ClassScanner ---- @Override - public void checkClass(ClassContext context, ClassNode classNode) { + public void checkClass(@NonNull ClassContext context, @NonNull ClassNode classNode) { // Abstract classes do not need to be registered if ((classNode.access & Opcodes.ACC_ABSTRACT) != 0) { return; diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ScrollViewChildDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ScrollViewChildDetector.java index 8ba2bc4..e5db5f1 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ScrollViewChildDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ScrollViewChildDetector.java @@ -24,6 +24,7 @@ import static com.android.tools.lint.detector.api.LintConstants.SCROLL_VIEW; import static com.android.tools.lint.detector.api.LintConstants.VALUE_FILL_PARENT; import static com.android.tools.lint.detector.api.LintConstants.VALUE_MATCH_PARENT; +import com.android.annotations.NonNull; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Issue; import com.android.tools.lint.detector.api.LayoutDetector; @@ -64,7 +65,7 @@ public class ScrollViewChildDetector extends LayoutDetector { } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @@ -77,13 +78,16 @@ public class ScrollViewChildDetector extends LayoutDetector { } @Override - public void visitElement(XmlContext context, Element element) { + public void visitElement(@NonNull XmlContext context, @NonNull Element element) { List<Element> children = LintUtils.getChildren(element); boolean isHorizontal = HORIZONTAL_SCROLL_VIEW.equals(element.getTagName()); String attributeName = isHorizontal ? ATTR_LAYOUT_WIDTH : ATTR_LAYOUT_HEIGHT; for (Element child : children) { Attr sizeNode = child.getAttributeNodeNS(ANDROID_URI, attributeName); - String value = sizeNode != null ? sizeNode.getValue() : null; + if (sizeNode == null) { + return; + } + String value = sizeNode.getValue(); if (VALUE_FILL_PARENT.equals(value) || VALUE_MATCH_PARENT.equals(value)) { String msg = String.format("This %1$s should use android:%2$s=\"wrap_content\"", child.getTagName(), attributeName); diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/SdCardDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/SdCardDetector.java index b239d57..d5e3a88 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/SdCardDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/SdCardDetector.java @@ -16,6 +16,7 @@ package com.android.tools.lint.checks; +import com.android.annotations.NonNull; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Context; import com.android.tools.lint.detector.api.Detector; @@ -59,12 +60,12 @@ public class SdCardDetector extends Detector implements Detector.JavaScanner { } @Override - public boolean appliesTo(Context context, File file) { + public boolean appliesTo(@NonNull Context context, @NonNull File file) { return true; } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @@ -76,7 +77,7 @@ public class SdCardDetector extends Detector implements Detector.JavaScanner { } @Override - public AstVisitor createJavaVisitor(JavaContext context) { + public AstVisitor createJavaVisitor(@NonNull JavaContext context) { return new StringChecker(context); } diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/SecurityDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/SecurityDetector.java index 807d515..c9848eb 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/SecurityDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/SecurityDetector.java @@ -32,6 +32,8 @@ import static com.android.tools.lint.detector.api.LintConstants.TAG_PATH_PERMISS import static com.android.tools.lint.detector.api.LintConstants.TAG_PROVIDER; import static com.android.tools.lint.detector.api.LintConstants.TAG_SERVICE; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Context; import com.android.tools.lint.detector.api.Detector; @@ -147,11 +149,11 @@ public class SecurityDetector extends Detector implements Detector.XmlScanner, } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @Override - public boolean appliesTo(Context context, File file) { + public boolean appliesTo(@NonNull Context context, @NonNull File file) { return file.getName().equals(ANDROID_MANIFEST_XML); } @@ -167,7 +169,7 @@ public class SecurityDetector extends Detector implements Detector.XmlScanner, } @Override - public void visitElement(XmlContext context, Element element) { + public void visitElement(@NonNull XmlContext context, @NonNull Element element) { String tag = element.getTagName(); if (tag.equals(TAG_SERVICE)) { checkService(context, element); @@ -264,7 +266,8 @@ public class SecurityDetector extends Detector implements Detector.XmlScanner, } if (!hasPermission) { - context.report(EXPORTED_PROVIDER, element, context.getLocation(element), + context.report(EXPORTED_PROVIDER, element, + context.getLocation(element), "Exported content providers can provide access to " + "potentially sensitive data", null); @@ -288,7 +291,8 @@ public class SecurityDetector extends Detector implements Detector.XmlScanner, } @Override - public void visitMethod(JavaContext context, AstVisitor visitor, MethodInvocation node) { + public void visitMethod(@NonNull JavaContext context, @Nullable AstVisitor visitor, + @NonNull MethodInvocation node) { StrictListAccessor<Expression,MethodInvocation> args = node.astArguments(); Iterator<Expression> iterator = args.iterator(); while (iterator.hasNext()) { @@ -297,7 +301,7 @@ public class SecurityDetector extends Detector implements Detector.XmlScanner, } @Override - public AstVisitor createJavaVisitor(JavaContext context) { + public AstVisitor createJavaVisitor(@NonNull JavaContext context) { return new IdentifierVisitor(context); } diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/SetJavaScriptEnabledDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/SetJavaScriptEnabledDetector.java index e711816..8653944 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/SetJavaScriptEnabledDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/SetJavaScriptEnabledDetector.java @@ -16,20 +16,20 @@ package com.android.tools.lint.checks; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Detector; import com.android.tools.lint.detector.api.Issue; import com.android.tools.lint.detector.api.JavaContext; 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 lombok.ast.MethodInvocation; import java.util.Collections; import java.util.List; import lombok.ast.AstVisitor; +import lombok.ast.MethodInvocation; /** * Looks for invocations of android.webkit.WebSettings.setJavaScriptEnabled. @@ -52,15 +52,11 @@ public class SetJavaScriptEnabledDetector extends Detector implements Detector.J public SetJavaScriptEnabledDetector() { } - @Override - public Speed getSpeed() { - return Speed.NORMAL; - } - // ---- Implements JavaScanner ---- @Override - public void visitMethod(JavaContext context, AstVisitor visitor, MethodInvocation node) { + public void visitMethod(@NonNull JavaContext context, @Nullable AstVisitor visitor, + @NonNull MethodInvocation node) { if (node.astArguments().size() == 1 && !node.astArguments().first().toString().equals("false")) { //$NON-NLS-1$ context.report(ISSUE, node, context.getLocation(node), diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/SharedPrefsDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/SharedPrefsDetector.java index 525ab6d..b8c86bf 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/SharedPrefsDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/SharedPrefsDetector.java @@ -15,6 +15,8 @@ */ package com.android.tools.lint.checks; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Context; import com.android.tools.lint.detector.api.Detector; @@ -22,7 +24,6 @@ import com.android.tools.lint.detector.api.Issue; import com.android.tools.lint.detector.api.JavaContext; 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 java.io.File; import java.util.Collections; @@ -61,16 +62,11 @@ public class SharedPrefsDetector extends Detector implements Detector.JavaScanne } @Override - public boolean appliesTo(Context context, File file) { + public boolean appliesTo(@NonNull Context context, @NonNull File file) { return true; } - @Override - public Speed getSpeed() { - return Speed.NORMAL; - } - // ---- Implements JavaScanner ---- @Override @@ -94,7 +90,8 @@ public class SharedPrefsDetector extends Detector implements Detector.JavaScanne } @Override - public void visitMethod(JavaContext context, AstVisitor visitor, MethodInvocation node) { + public void visitMethod(@NonNull JavaContext context, @Nullable AstVisitor visitor, + @NonNull MethodInvocation node) { assert node.astName().astValue().equals("edit"); if (node.astOperand() == null) { return; diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/StateListDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/StateListDetector.java index 3235c9a..d7f0d99 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/StateListDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/StateListDetector.java @@ -18,6 +18,7 @@ package com.android.tools.lint.checks; import static com.android.tools.lint.detector.api.LintConstants.ANDROID_URI; +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.Issue; @@ -57,17 +58,17 @@ public class StateListDetector extends ResourceXmlDetector { } @Override - public boolean appliesTo(ResourceFolderType folderType) { + public boolean appliesTo(@NonNull ResourceFolderType folderType) { return folderType == ResourceFolderType.DRAWABLE; } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @Override - public void visitDocument(XmlContext context, Document document) { + public void visitDocument(@NonNull XmlContext context, @NonNull Document document) { // TODO: Look for views that don't specify // Display the error token somewhere so it can be suppressed // Emit warning at the end "run with --help to learn how to suppress types of errors/checks"; diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/StringFormatDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/StringFormatDetector.java index 5fae363..f5d6d80 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/StringFormatDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/StringFormatDetector.java @@ -20,6 +20,8 @@ import static com.android.tools.lint.detector.api.LintConstants.ATTR_NAME; import static com.android.tools.lint.detector.api.LintConstants.DOT_JAVA; import static com.android.tools.lint.detector.api.LintConstants.TAG_STRING; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.annotations.VisibleForTesting; import com.android.resources.ResourceFolderType; import com.android.tools.lint.client.api.IJavaParser; @@ -35,7 +37,6 @@ import com.android.tools.lint.detector.api.Position; 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 com.android.util.Pair; @@ -162,12 +163,12 @@ public class StringFormatDetector extends ResourceXmlDetector implements Detecto } @Override - public boolean appliesTo(ResourceFolderType folderType) { + public boolean appliesTo(@NonNull ResourceFolderType folderType) { return folderType == ResourceFolderType.VALUES; } @Override - public boolean appliesTo(Context context, File file) { + public boolean appliesTo(@NonNull Context context, @NonNull File file) { if (LintUtils.endsWith(file.getName(), DOT_JAVA)) { return mFormatStrings != null; } @@ -176,17 +177,12 @@ public class StringFormatDetector extends ResourceXmlDetector implements Detecto } @Override - public Speed getSpeed() { - return Speed.NORMAL; - } - - @Override public Collection<String> getApplicableElements() { return Collections.singletonList(TAG_STRING); } @Override - public void visitElement(XmlContext context, Element element) { + public void visitElement(@NonNull XmlContext context, @NonNull Element element) { NodeList childNodes = element.getChildNodes(); if (childNodes.getLength() > 0) { if (childNodes.getLength() == 1) { @@ -309,7 +305,7 @@ public class StringFormatDetector extends ResourceXmlDetector implements Detecto } @Override - public void afterCheckProject(Context context) { + public void afterCheckProject(@NonNull Context context) { if (mFormatStrings != null) { Formatter formatter = new Formatter(); @@ -773,7 +769,8 @@ public class StringFormatDetector extends ResourceXmlDetector implements Detecto } @Override - public void visitMethod(JavaContext context, AstVisitor visitor, MethodInvocation node) { + public void visitMethod(@NonNull JavaContext context, @Nullable AstVisitor visitor, + @NonNull MethodInvocation node) { if (mFormatStrings == null) { return; } diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/StyleCycleDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/StyleCycleDetector.java index f248d6e..03766b7 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/StyleCycleDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/StyleCycleDetector.java @@ -21,6 +21,7 @@ import static com.android.tools.lint.detector.api.LintConstants.ATTR_PARENT; import static com.android.tools.lint.detector.api.LintConstants.STYLE_RESOURCE_PREFIX; import static com.android.tools.lint.detector.api.LintConstants.TAG_STYLE; +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.Issue; @@ -58,12 +59,12 @@ public class StyleCycleDetector extends ResourceXmlDetector { } @Override - public boolean appliesTo(ResourceFolderType folderType) { + public boolean appliesTo(@NonNull ResourceFolderType folderType) { return folderType == ResourceFolderType.VALUES; } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @@ -73,7 +74,7 @@ public class StyleCycleDetector extends ResourceXmlDetector { } @Override - public void visitElement(XmlContext context, Element element) { + public void visitElement(@NonNull XmlContext context, @NonNull Element element) { Attr parentNode = element.getAttributeNode(ATTR_PARENT); if (parentNode != null) { String parent = parentNode.getValue(); diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/TextFieldDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/TextFieldDetector.java index 2cc81ab..c133ce2 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/TextFieldDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/TextFieldDetector.java @@ -22,6 +22,7 @@ import static com.android.tools.lint.detector.api.LintConstants.ATTR_INPUT_METHO import static com.android.tools.lint.detector.api.LintConstants.ATTR_INPUT_TYPE; import static com.android.tools.lint.detector.api.LintConstants.EDIT_TEXT; +import com.android.annotations.NonNull; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Issue; import com.android.tools.lint.detector.api.LayoutDetector; @@ -63,7 +64,7 @@ public class TextFieldDetector extends LayoutDetector { } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @@ -73,7 +74,7 @@ public class TextFieldDetector extends LayoutDetector { } @Override - public void visitElement(XmlContext context, Element element) { + public void visitElement(@NonNull XmlContext context, @NonNull Element element) { if (!element.hasAttributeNS(ANDROID_URI, ATTR_INPUT_TYPE) && !element.hasAttributeNS(ANDROID_URI, ATTR_HINT)) { // Also make sure the EditText does not set an inputMethod in which case diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/TextViewDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/TextViewDetector.java index 09608b1..e6e0371 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/TextViewDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/TextViewDetector.java @@ -44,6 +44,7 @@ import static com.android.tools.lint.detector.api.LintConstants.VALUE_EDITABLE; import static com.android.tools.lint.detector.api.LintConstants.VALUE_NONE; import static com.android.tools.lint.detector.api.LintConstants.VALUE_TRUE; +import com.android.annotations.NonNull; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Issue; import com.android.tools.lint.detector.api.LayoutDetector; @@ -91,7 +92,7 @@ public class TextViewDetector extends LayoutDetector { } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @@ -109,7 +110,7 @@ public class TextViewDetector extends LayoutDetector { } @Override - public void visitElement(XmlContext context, Element element) { + public void visitElement(@NonNull XmlContext context, @NonNull Element element) { NamedNodeMap attributes = element.getAttributes(); for (int i = 0, n = attributes.getLength(); i < n; i++) { Attr attribute = (Attr) attributes.item(i); diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ToastDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ToastDetector.java index f199438..d876c53 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ToastDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ToastDetector.java @@ -15,6 +15,8 @@ */ package com.android.tools.lint.checks; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Context; import com.android.tools.lint.detector.api.Detector; @@ -22,7 +24,6 @@ import com.android.tools.lint.detector.api.Issue; import com.android.tools.lint.detector.api.JavaContext; 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 java.io.File; import java.util.Collections; @@ -60,16 +61,11 @@ public class ToastDetector extends Detector implements Detector.JavaScanner { } @Override - public boolean appliesTo(Context context, File file) { + public boolean appliesTo(@NonNull Context context, @NonNull File file) { return true; } - @Override - public Speed getSpeed() { - return Speed.NORMAL; - } - // ---- Implements JavaScanner ---- @Override @@ -93,7 +89,8 @@ public class ToastDetector extends Detector implements Detector.JavaScanner { } @Override - public void visitMethod(JavaContext context, AstVisitor visitor, MethodInvocation node) { + public void visitMethod(@NonNull JavaContext context, @Nullable AstVisitor visitor, + @NonNull MethodInvocation node) { assert node.astName().astValue().equals("makeText"); if (node.astOperand() == null) { // "makeText()" in the code with no operand diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/TooManyViewsDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/TooManyViewsDetector.java index 257d06c..ed3480a 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/TooManyViewsDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/TooManyViewsDetector.java @@ -16,6 +16,7 @@ package com.android.tools.lint.checks; +import com.android.annotations.NonNull; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Context; import com.android.tools.lint.detector.api.Issue; @@ -102,12 +103,12 @@ public class TooManyViewsDetector extends LayoutDetector { } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @Override - public void beforeCheckFile(Context context) { + public void beforeCheckFile(@NonNull Context context) { mViewCount = mDepth = 0; mWarnedAboutDepth = false; } @@ -118,7 +119,7 @@ public class TooManyViewsDetector extends LayoutDetector { } @Override - public void visitElement(XmlContext context, Element element) { + public void visitElement(@NonNull XmlContext context, @NonNull Element element) { mViewCount++; mDepth++; @@ -140,7 +141,7 @@ public class TooManyViewsDetector extends LayoutDetector { } @Override - public void visitElementAfter(XmlContext context, Element element) { + public void visitElementAfter(@NonNull XmlContext context, @NonNull Element element) { mDepth--; } } diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/TranslationDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/TranslationDetector.java index 98d56b0..70e0723 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/TranslationDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/TranslationDetector.java @@ -24,6 +24,7 @@ import static com.android.tools.lint.detector.api.LintConstants.TAG_ITEM; import static com.android.tools.lint.detector.api.LintConstants.TAG_STRING; import static com.android.tools.lint.detector.api.LintConstants.TAG_STRING_ARRAY; +import com.android.annotations.NonNull; import com.android.annotations.VisibleForTesting; import com.android.resources.ResourceFolderType; import com.android.tools.lint.detector.api.Category; @@ -33,7 +34,6 @@ 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 com.google.common.collect.Sets; @@ -116,16 +116,11 @@ public class TranslationDetector extends ResourceXmlDetector { } @Override - public boolean appliesTo(ResourceFolderType folderType) { + public boolean appliesTo(@NonNull ResourceFolderType folderType) { return folderType == ResourceFolderType.VALUES; } @Override - public Speed getSpeed() { - return Speed.NORMAL; - } - - @Override public Collection<String> getApplicableElements() { return Arrays.asList( TAG_STRING, @@ -134,14 +129,14 @@ public class TranslationDetector extends ResourceXmlDetector { } @Override - public void beforeCheckProject(Context context) { + public void beforeCheckProject(@NonNull Context context) { if (context.getDriver().getPhase() == 1) { mFileToNames = new HashMap<File, Set<String>>(); } } @Override - public void beforeCheckFile(Context context) { + public void beforeCheckFile(@NonNull Context context) { if (context.getPhase() == 1) { mNames = new HashSet<String>(); } @@ -151,7 +146,7 @@ public class TranslationDetector extends ResourceXmlDetector { } @Override - public void afterCheckFile(Context context) { + public void afterCheckFile(@NonNull Context context) { if (context.getPhase() == 1) { // Store this layout's set of ids for full project analysis in afterCheckProject mFileToNames.put(context.file, mNames); @@ -161,7 +156,7 @@ public class TranslationDetector extends ResourceXmlDetector { } @Override - public void afterCheckProject(Context context) { + public void afterCheckProject(@NonNull Context context) { if (context.getPhase() == 1) { // NOTE - this will look for the presence of translation strings. // If you create a resource folder but don't actually place a file in it @@ -406,7 +401,7 @@ public class TranslationDetector extends ResourceXmlDetector { } @Override - public void visitElement(XmlContext context, Element element) { + public void visitElement(@NonNull XmlContext context, @NonNull Element element) { if (mIgnoreFile) { return; } diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/TypographyDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/TypographyDetector.java index c5a9302..5ad52b3 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/TypographyDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/TypographyDetector.java @@ -19,6 +19,7 @@ package com.android.tools.lint.checks; import static com.android.tools.lint.detector.api.LintConstants.TAG_STRING; import static com.android.tools.lint.detector.api.LintConstants.TAG_STRING_ARRAY; +import com.android.annotations.NonNull; import com.android.annotations.VisibleForTesting; import com.android.resources.ResourceFolderType; import com.android.tools.lint.detector.api.Category; @@ -192,12 +193,12 @@ public class TypographyDetector extends ResourceXmlDetector { } @Override - public boolean appliesTo(ResourceFolderType folderType) { + public boolean appliesTo(@NonNull ResourceFolderType folderType) { return folderType == ResourceFolderType.VALUES; } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @@ -210,7 +211,7 @@ public class TypographyDetector extends ResourceXmlDetector { } @Override - public void beforeCheckProject(Context context) { + public void beforeCheckProject(@NonNull Context context) { mCheckDashes = context.isEnabled(DASHES); mCheckQuotes = context.isEnabled(QUOTES); mCheckFractions = context.isEnabled(FRACTIONS); @@ -219,7 +220,7 @@ public class TypographyDetector extends ResourceXmlDetector { } @Override - public void visitElement(XmlContext context, Element element) { + public void visitElement(@NonNull XmlContext context, @NonNull Element element) { NodeList childNodes = element.getChildNodes(); for (int i = 0, n = childNodes.getLength(); i < n; i++) { Node child = childNodes.item(i); diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/UnusedResourceDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/UnusedResourceDetector.java index 3ea1c14..f9b5a67 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/UnusedResourceDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/UnusedResourceDetector.java @@ -38,6 +38,8 @@ import static com.android.tools.lint.detector.api.LintConstants.TAG_STRING_ARRAY import static com.android.tools.lint.detector.api.LintConstants.TAG_STYLE; import static com.android.tools.lint.detector.api.LintUtils.endsWith; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.resources.ResourceType; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Context; @@ -121,17 +123,17 @@ public class UnusedResourceDetector extends ResourceXmlDetector implements Detec } @Override - public void run(Context context) { + public void run(@NonNull Context context) { assert false; } @Override - public boolean appliesTo(Context context, File file) { + public boolean appliesTo(@NonNull Context context, @NonNull File file) { return true; } @Override - public void beforeCheckProject(Context context) { + public void beforeCheckProject(@NonNull Context context) { if (context.getPhase() == 1) { mDeclarations = new HashSet<String>(300); mReferences = new HashSet<String>(300); @@ -141,7 +143,7 @@ public class UnusedResourceDetector extends ResourceXmlDetector implements Detec // ---- Implements JavaScanner ---- @Override - public void beforeCheckFile(Context context) { + public void beforeCheckFile(@NonNull Context context) { File file = context.file; String fileName = file.getName(); @@ -188,7 +190,7 @@ public class UnusedResourceDetector extends ResourceXmlDetector implements Detec } @Override - public void afterCheckProject(Context context) { + public void afterCheckProject(@NonNull Context context) { if (context.getPhase() == 1) { mDeclarations.removeAll(mReferences); Set<String> unused = mDeclarations; @@ -330,7 +332,7 @@ public class UnusedResourceDetector extends ResourceXmlDetector implements Detec } @Override - public void visitElement(XmlContext context, Element element) { + public void visitElement(@NonNull XmlContext context, @NonNull Element element) { if (TAG_RESOURCES.equals(element.getTagName())) { for (Element item : LintUtils.getChildren(element)) { String name = item.getAttribute(ATTR_NAME); @@ -401,7 +403,7 @@ public class UnusedResourceDetector extends ResourceXmlDetector implements Detec } @Override - public void visitAttribute(XmlContext context, Attr attribute) { + public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) { String value = attribute.getValue(); if (value.startsWith("@+") && !value.startsWith("@+android")) { //$NON-NLS-1$ //$NON-NLS-2$ @@ -437,7 +439,7 @@ public class UnusedResourceDetector extends ResourceXmlDetector implements Detec } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.SLOW; } @@ -452,8 +454,9 @@ public class UnusedResourceDetector extends ResourceXmlDetector implements Detec } @Override - public void visitResourceReference(JavaContext context, AstVisitor visitor, - lombok.ast.Node node, String type, String name, boolean isFramework) { + public void visitResourceReference(@NonNull JavaContext context, @Nullable AstVisitor visitor, + @NonNull lombok.ast.Node node, @NonNull String type, @NonNull String name, + boolean isFramework) { if (mReferences != null && !isFramework) { String reference = R_PREFIX + type + '.' + name; mReferences.add(reference); @@ -461,7 +464,7 @@ public class UnusedResourceDetector extends ResourceXmlDetector implements Detec } @Override - public AstVisitor createJavaVisitor(JavaContext context) { + public AstVisitor createJavaVisitor(@NonNull JavaContext context) { if (mReferences != null) { return new UnusedResourceVisitor(); } else { diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/UseCompoundDrawableDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/UseCompoundDrawableDetector.java index 540a0f1..d091ce1 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/UseCompoundDrawableDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/UseCompoundDrawableDetector.java @@ -23,6 +23,7 @@ import static com.android.tools.lint.detector.api.LintConstants.IMAGE_VIEW; import static com.android.tools.lint.detector.api.LintConstants.LINEAR_LAYOUT; import static com.android.tools.lint.detector.api.LintConstants.TEXT_VIEW; +import com.android.annotations.NonNull; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Issue; import com.android.tools.lint.detector.api.LayoutDetector; @@ -63,7 +64,7 @@ public class UseCompoundDrawableDetector extends LayoutDetector { } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @@ -75,7 +76,7 @@ public class UseCompoundDrawableDetector extends LayoutDetector { } @Override - public void visitElement(XmlContext context, Element element) { + public void visitElement(@NonNull XmlContext context, @NonNull Element element) { int childCount = LintUtils.getChildCount(element); if (childCount == 2) { List<Element> children = LintUtils.getChildren(element); diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/UselessViewDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/UselessViewDetector.java index fd4ff58..b913588 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/UselessViewDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/UselessViewDetector.java @@ -33,6 +33,7 @@ import static com.android.tools.lint.detector.api.LintConstants.SCROLL_VIEW; import static com.android.tools.lint.detector.api.LintConstants.TABLE_LAYOUT; import static com.android.tools.lint.detector.api.LintConstants.TABLE_ROW; +import com.android.annotations.NonNull; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Issue; import com.android.tools.lint.detector.api.LayoutDetector; @@ -85,7 +86,7 @@ public class UselessViewDetector extends LayoutDetector { } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @@ -127,7 +128,7 @@ public class UselessViewDetector extends LayoutDetector { } @Override - public void visitElement(XmlContext context, Element element) { + public void visitElement(@NonNull XmlContext context, @NonNull Element element) { int childCount = LintUtils.getChildCount(element); if (childCount == 0) { // Check to see if this is a leaf layout that can be removed diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/Utf8Detector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/Utf8Detector.java index 6a87e94..875de62 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/Utf8Detector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/Utf8Detector.java @@ -16,6 +16,7 @@ package com.android.tools.lint.checks; +import com.android.annotations.NonNull; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Issue; import com.android.tools.lint.detector.api.LayoutDetector; @@ -57,12 +58,12 @@ public class Utf8Detector extends LayoutDetector { } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @Override - public void visitDocument(XmlContext context, Document document) { + public void visitDocument(@NonNull XmlContext context, @NonNull Document document) { String xml = context.getContents(); // AAPT: The prologue must be in the first line diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ViewConstructorDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ViewConstructorDetector.java index 6c3b42a..538c0d6 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ViewConstructorDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ViewConstructorDetector.java @@ -16,6 +16,9 @@ package com.android.tools.lint.checks; +import static com.android.tools.lint.detector.api.LintConstants.CONSTRUCTOR_NAME; + +import com.android.annotations.NonNull; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.ClassContext; import com.android.tools.lint.detector.api.Context; @@ -71,19 +74,19 @@ public class ViewConstructorDetector extends Detector implements Detector.ClassS } @Override - public boolean appliesTo(Context context, File file) { + public boolean appliesTo(@NonNull Context context, @NonNull File file) { return true; } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } // ---- Implements ClassScanner ---- @Override - public void checkClass(ClassContext context, ClassNode classNode) { + public void checkClass(@NonNull ClassContext context, @NonNull ClassNode classNode) { if (classNode.name.indexOf('$') != -1 && (classNode.access & Opcodes.ACC_STATIC) == 0) { // Ignore inner classes that aren't static: we can't create these @@ -122,7 +125,7 @@ public class ViewConstructorDetector extends Detector implements Detector.ClassS List methods = classNode.methods; for (Object methodObject : methods) { MethodNode method = (MethodNode) methodObject; - if (method.name.equals("<init>")) { //$NON-NLS-1$ + if (method.name.equals(CONSTRUCTOR_NAME)) { String desc = method.desc; if (desc.equals(SIG1) || desc.equals(SIG2) || desc.equals(SIG3)) { return; diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ViewTypeDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ViewTypeDetector.java index 78a06af..30def17 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/ViewTypeDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/ViewTypeDetector.java @@ -23,6 +23,8 @@ import static com.android.tools.lint.detector.api.LintConstants.ID_RESOURCE_PREF import static com.android.tools.lint.detector.api.LintConstants.NEW_ID_RESOURCE_PREFIX; import static com.android.tools.lint.detector.api.LintConstants.VIEW_TAG; +import com.android.annotations.NonNull; +import com.android.annotations.Nullable; import com.android.resources.ResourceFolderType; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Context; @@ -69,17 +71,17 @@ public class ViewTypeDetector extends ResourceXmlDetector implements Detector.Ja private Map<String, String> mIdToViewTag = new HashMap<String, String>(50); @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.SLOW; } @Override - public boolean appliesTo(ResourceFolderType folderType) { + public boolean appliesTo(@NonNull ResourceFolderType folderType) { return folderType == ResourceFolderType.LAYOUT; } @Override - public boolean appliesTo(Context context, File file) { + public boolean appliesTo(@NonNull Context context, @NonNull File file) { if (LintUtils.endsWith(file.getName(), DOT_JAVA)) { return true; } @@ -100,7 +102,7 @@ public class ViewTypeDetector extends ResourceXmlDetector implements Detector.Ja private static final String IGNORE = "#ignore#"; @Override - public void visitAttribute(XmlContext context, Attr attribute) { + public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) { String view = attribute.getOwnerElement().getTagName(); String value = attribute.getValue(); String id = null; @@ -131,7 +133,8 @@ public class ViewTypeDetector extends ResourceXmlDetector implements Detector.Ja } @Override - public void visitMethod(JavaContext context, AstVisitor visitor, MethodInvocation node) { + public void visitMethod(@NonNull JavaContext context, @Nullable AstVisitor visitor, + @NonNull MethodInvocation node) { assert node.astName().getDescription().equals("findViewById"); if (node.getParent() instanceof Cast) { Cast cast = (Cast) node.getParent(); diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/WrongIdDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/WrongIdDetector.java index ef45c09..a9652d1 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/WrongIdDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/WrongIdDetector.java @@ -28,6 +28,7 @@ import static com.android.tools.lint.detector.api.LintConstants.TAG_ITEM; import static com.android.tools.lint.detector.api.LintConstants.VALUE_ID; import static com.android.tools.lint.detector.api.LintUtils.stripIdPrefix; +import com.android.annotations.NonNull; import com.android.resources.ResourceFolderType; import com.android.tools.lint.client.api.IDomParser; import com.android.tools.lint.detector.api.Category; @@ -127,12 +128,12 @@ public class WrongIdDetector extends LayoutDetector { } @Override - public boolean appliesTo(ResourceFolderType folderType) { + public boolean appliesTo(@NonNull ResourceFolderType folderType) { return folderType == ResourceFolderType.LAYOUT || folderType == ResourceFolderType.VALUES; } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @@ -147,13 +148,13 @@ public class WrongIdDetector extends LayoutDetector { } @Override - public void beforeCheckFile(Context context) { + public void beforeCheckFile(@NonNull Context context) { mFileIds = new HashSet<String>(); mRelativeLayouts = null; } @Override - public void afterCheckFile(Context context) { + public void afterCheckFile(@NonNull Context context) { if (mRelativeLayouts != null) { for (Element layout : mRelativeLayouts) { NodeList children = layout.getChildNodes(); @@ -196,7 +197,7 @@ public class WrongIdDetector extends LayoutDetector { } @Override - public void afterCheckProject(Context context) { + public void afterCheckProject(@NonNull Context context) { if (mHandles != null) { boolean checkSameLayout = context.isEnabled(UNKNOWN_ID_LAYOUT); boolean checkExists = context.isEnabled(UNKNOWN_ID); @@ -257,7 +258,7 @@ public class WrongIdDetector extends LayoutDetector { } @Override - public void visitElement(XmlContext context, Element element) { + public void visitElement(@NonNull XmlContext context, @NonNull Element element) { if (element.getTagName().equals(RELATIVE_LAYOUT)) { if (mRelativeLayouts == null) { mRelativeLayouts = new ArrayList<Element>(); @@ -279,7 +280,7 @@ public class WrongIdDetector extends LayoutDetector { } @Override - public void visitAttribute(XmlContext context, Attr attribute) { + public void visitAttribute(@NonNull XmlContext context, @NonNull Attr attribute) { assert attribute.getName().equals(ATTR_ID) || attribute.getLocalName().equals(ATTR_ID); String id = attribute.getValue(); mFileIds.add(id); diff --git a/lint/libs/lint_checks/src/com/android/tools/lint/checks/WrongImportDetector.java b/lint/libs/lint_checks/src/com/android/tools/lint/checks/WrongImportDetector.java index 2aa416c..fc6cde2 100644 --- a/lint/libs/lint_checks/src/com/android/tools/lint/checks/WrongImportDetector.java +++ b/lint/libs/lint_checks/src/com/android/tools/lint/checks/WrongImportDetector.java @@ -16,6 +16,7 @@ package com.android.tools.lint.checks; +import com.android.annotations.NonNull; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Detector; import com.android.tools.lint.detector.api.Issue; @@ -67,7 +68,7 @@ public class WrongImportDetector extends Detector implements Detector.JavaScanne } @Override - public Speed getSpeed() { + public @NonNull Speed getSpeed() { return Speed.FAST; } @@ -80,7 +81,7 @@ public class WrongImportDetector extends Detector implements Detector.JavaScanne } @Override - public AstVisitor createJavaVisitor(JavaContext context) { + public AstVisitor createJavaVisitor(@NonNull JavaContext context) { return new ImportVisitor(context); } diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/FragmentDetectorTest.java b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/FragmentDetectorTest.java new file mode 100644 index 0000000..e25bbbc --- /dev/null +++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/FragmentDetectorTest.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php + * + * 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 FragmentDetectorTest extends AbstractCheckTest { + @Override + protected Detector getDetector() { + return new FragmentDetector(); + } + + public void test() throws Exception { + assertEquals( + "FragmentTest.java:10: Warning: This fragment class should be public (test.pkg.FragmentTest.Fragment1)\n" + + "FragmentTest.java:15: Warning: This fragment inner class should be static (test.pkg.FragmentTest.Fragment2)\n" + + "FragmentTest.java:21: Warning: The default constructor must be public\n" + + "FragmentTest.java:27: Warning: Avoid non-default constructors in fragments: use a default constructor plus Fragment#setArguments(Bundle) instead\n" + + "FragmentTest.java:27: Warning: This fragment should provide a default constructor (a public constructor with no arguments) (test.pkg.FragmentTest.Fragment4)\n" + + "FragmentTest.java:36: Warning: Avoid non-default constructors in fragments: use a default constructor plus Fragment#setArguments(Bundle) instead", + + lintProject( + "bytecode/FragmentTest$Fragment1.class.data=>bin/classes/test/pkg/FragmentTest$Fragment1.class", + "bytecode/FragmentTest$Fragment2.class.data=>bin/classes/test/pkg/FragmentTest$Fragment2.class", + "bytecode/FragmentTest$Fragment3.class.data=>bin/classes/test/pkg/FragmentTest$Fragment3.class", + "bytecode/FragmentTest$Fragment4.class.data=>bin/classes/test/pkg/FragmentTest$Fragment4.class", + "bytecode/FragmentTest$Fragment5.class.data=>bin/classes/test/pkg/FragmentTest$Fragment5.class", + "bytecode/FragmentTest$Fragment6.class.data=>bin/classes/test/pkg/FragmentTest$Fragment6.class", + "bytecode/FragmentTest$NotAFragment.class.data=>bin/classes/test/pkg/FragmentTest$NotAFragment.class", + "bytecode/FragmentTest.java.txt=>src/test/pkg/FragmentTest.java")); + } +} diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/HandlerDetectorTest.java b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/HandlerDetectorTest.java index 1631a23..979a7b0 100644 --- a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/HandlerDetectorTest.java +++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/HandlerDetectorTest.java @@ -27,8 +27,8 @@ public class HandlerDetectorTest extends AbstractCheckTest { public void testRegistered() throws Exception { assertEquals( - "HandlerTest$1.class: Warning: This Handler class should be static or leaks might occur (test.pkg.HandlerTest.1)\n" + - "HandlerTest$Inner.class: Warning: This Handler class should be static or leaks might occur (test.pkg.HandlerTest.Inner)", + "HandlerTest.java:14: Warning: This Handler class should be static or leaks might occur (test.pkg.HandlerTest.Inner)\n" + + "HandlerTest.java:20: Warning: This Handler class should be static or leaks might occur (test.pkg.HandlerTest.1)", lintProject( "bytecode/HandlerTest.java.txt=>src/test/pkg/HandlerTest.java", diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/FragmentTest$Fragment1.class.data b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/FragmentTest$Fragment1.class.data Binary files differnew file mode 100644 index 0000000..11a98dd --- /dev/null +++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/FragmentTest$Fragment1.class.data diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/FragmentTest$Fragment2.class.data b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/FragmentTest$Fragment2.class.data Binary files differnew file mode 100644 index 0000000..d77579a --- /dev/null +++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/FragmentTest$Fragment2.class.data diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/FragmentTest$Fragment3.class.data b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/FragmentTest$Fragment3.class.data Binary files differnew file mode 100644 index 0000000..b1ec17d --- /dev/null +++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/FragmentTest$Fragment3.class.data diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/FragmentTest$Fragment4.class.data b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/FragmentTest$Fragment4.class.data Binary files differnew file mode 100644 index 0000000..f89f8ed --- /dev/null +++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/FragmentTest$Fragment4.class.data diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/FragmentTest$Fragment5.class.data b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/FragmentTest$Fragment5.class.data Binary files differnew file mode 100644 index 0000000..4a23e03 --- /dev/null +++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/FragmentTest$Fragment5.class.data diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/FragmentTest$Fragment6.class.data b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/FragmentTest$Fragment6.class.data Binary files differnew file mode 100644 index 0000000..2e10e12 --- /dev/null +++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/FragmentTest$Fragment6.class.data diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/FragmentTest$NotAFragment.class.data b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/FragmentTest$NotAFragment.class.data Binary files differnew file mode 100644 index 0000000..8f5b827 --- /dev/null +++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/FragmentTest$NotAFragment.class.data diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/FragmentTest$ValidFragment1.class.data b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/FragmentTest$ValidFragment1.class.data Binary files differnew file mode 100644 index 0000000..a3354a7 --- /dev/null +++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/FragmentTest$ValidFragment1.class.data diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/FragmentTest.class.data b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/FragmentTest.class.data Binary files differnew file mode 100644 index 0000000..6cc8387 --- /dev/null +++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/FragmentTest.class.data diff --git a/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/FragmentTest.java.txt b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/FragmentTest.java.txt new file mode 100644 index 0000000..d27c04a --- /dev/null +++ b/lint/libs/lint_checks/tests/src/com/android/tools/lint/checks/data/bytecode/FragmentTest.java.txt @@ -0,0 +1,55 @@ +package test.pkg; + +import android.annotation.SuppressLint; +import android.app.Fragment; + +@SuppressWarnings("unused") +public class FragmentTest { + + // Should be public + private static class Fragment1 extends Fragment { + + } + + // Should be static + public class Fragment2 extends Fragment { + + } + + // Should have a public constructor + public static class Fragment3 extends Fragment { + private Fragment3() { + } + } + + // Should have a public constructor with no arguments + public static class Fragment4 extends Fragment { + private Fragment4(int dummy) { + } + } + + // Should *only* have the default constructor, not the + // multi-argument one + public static class Fragment5 extends Fragment { + public Fragment5() { + } + public Fragment5(int dummy) { + } + } + + // Suppressed + @SuppressLint("ValidFragment") + public static class Fragment6 extends Fragment { + private Fragment6() { + } + } + + public static class ValidFragment1 extends Fragment { + public ValidFragment1() { + } + } + + // (Not a fragment) + private class NotAFragment { + } +} diff --git a/monitor/Android.mk b/monitor/Android.mk index 2661dc6..9973d64 100644 --- a/monitor/Android.mk +++ b/monitor/Android.mk @@ -23,11 +23,14 @@ define mk-rcp-monitor-atree-file unzip -q $$srczip -d $$dstdir endef +MONITOR_DEP_LIBRARIES := $(shell $(TOPDIR)sdk/eclipse/scripts/create_all_symlinks.sh -d) +MONITOR_DEPS := $(foreach m,$(MONITOR_DEP_LIBRARIES),$(HOST_OUT_JAVA_LIBRARIES)/$(m).jar) + # The RCP monitor. It is referenced by build/target/products/sdk.mk $(LOCAL_BUILT_MODULE) : $(TOPDIR)sdk/monitor/monitor \ $(TOPDIR)sdk/monitor/build.xml \ $(TOPDIR)sdk/monitor/build.properties \ - $(shell $(TOPDIR)sdk/eclipse/scripts/create_all_symlinks.sh -d) + $(MONITOR_DEPS) @mkdir -p $(dir $@) $(hide)$(TOPDIR)sdk/eclipse/scripts/create_all_symlinks.sh -c $(hide)cd $(TOPDIR)sdk/monitor && \ @@ -54,6 +57,6 @@ $(LOCAL_BUILT_MODULE) : $(TOPDIR)sdk/monitor/monitor \ $(call mk-rcp-monitor-atree-file,win32.win32,x86) ; \ $(call mk-rcp-monitor-atree-file,win32.win32,x86_64) ; \ fi - $(hide)$(ACP) -fpt $(V) $(TOPDIR)sdk/monitor/monitor $@ + $(hide)$(ACP) -fp $(V) $(TOPDIR)sdk/monitor/monitor $@ endif diff --git a/rule_api/src/com/android/ide/common/api/AbstractViewRule.java b/rule_api/src/com/android/ide/common/api/AbstractViewRule.java index 3bbf8e7..7f05809 100644 --- a/rule_api/src/com/android/ide/common/api/AbstractViewRule.java +++ b/rule_api/src/com/android/ide/common/api/AbstractViewRule.java @@ -15,6 +15,7 @@ */ package com.android.ide.common.api; +import com.android.annotations.NonNull; import com.android.annotations.Nullable; import com.google.common.annotations.Beta; @@ -31,7 +32,7 @@ import java.util.List; @Beta public class AbstractViewRule implements IViewRule { @Override - public boolean onInitialize(String fqcn, IClientRulesEngine engine) { + public boolean onInitialize(@NonNull String fqcn, @NonNull IClientRulesEngine engine) { return true; } @@ -50,22 +51,22 @@ public class AbstractViewRule implements IViewRule { @Override @Nullable - public List<String> getSelectionHint(INode parentNode, INode childNode) { + public List<String> getSelectionHint(@NonNull INode parentNode, @NonNull INode childNode) { return null; } @Override - public void addLayoutActions(List<RuleAction> actions, INode parentNode, - List<? extends INode> children) { + public void addLayoutActions(@NonNull List<RuleAction> actions, @NonNull INode parentNode, + @NonNull List<? extends INode> children) { } @Override - public void addContextMenuActions(List<RuleAction> actions, INode node) { + public void addContextMenuActions(@NonNull List<RuleAction> actions, @NonNull INode node) { } @Override - public void paintSelectionFeedback(IGraphics graphics, INode parentNode, - List<? extends INode> childNodes, Object view) { + public void paintSelectionFeedback(@NonNull IGraphics graphics, @NonNull INode parentNode, + @NonNull List<? extends INode> childNodes, @Nullable Object view) { } // ==== Drag & drop support ==== @@ -73,66 +74,66 @@ public class AbstractViewRule implements IViewRule { // By default Views do not accept drag'n'drop. @Override @Nullable - public DropFeedback onDropEnter(INode targetNode, Object targetView, IDragElement[] elements) { + public DropFeedback onDropEnter(@NonNull INode targetNode, @Nullable Object targetView, @Nullable IDragElement[] elements) { return null; } @Override @Nullable - public DropFeedback onDropMove(INode targetNode, IDragElement[] elements, - DropFeedback feedback, Point p) { + public DropFeedback onDropMove(@NonNull INode targetNode, @NonNull IDragElement[] elements, + @Nullable DropFeedback feedback, @NonNull Point p) { return null; } @Override - public void onDropLeave(INode targetNode, IDragElement[] elements, DropFeedback feedback) { + public void onDropLeave(@NonNull INode targetNode, @NonNull IDragElement[] elements, @Nullable DropFeedback feedback) { // ignore } @Override public void onDropped( - INode targetNode, - IDragElement[] elements, - DropFeedback feedback, - Point p) { + @NonNull INode targetNode, + @NonNull IDragElement[] elements, + @Nullable DropFeedback feedback, + @NonNull Point p) { // ignore } @Override - public void onPaste(INode targetNode, Object targetView, IDragElement[] pastedElements) { + public void onPaste(@NonNull INode targetNode, @Nullable Object targetView, @NonNull IDragElement[] pastedElements) { } // ==== Create/Remove hooks ==== @Override - public void onCreate(INode node, INode parent, InsertType insertType) { + public void onCreate(@NonNull INode node, @NonNull INode parent, @NonNull InsertType insertType) { } @Override - public void onChildInserted(INode child, INode parent, InsertType insertType) { + public void onChildInserted(@NonNull INode child, @NonNull INode parent, @NonNull InsertType insertType) { } @Override - public void onRemovingChildren(List<INode> deleted, INode parent) { + public void onRemovingChildren(@NonNull List<INode> deleted, @NonNull INode parent) { } // ==== Resizing ==== @Override @Nullable - public DropFeedback onResizeBegin(INode child, INode parent, SegmentType horizontalEdge, - SegmentType verticalEdge, Object childView, Object parentView) { + public DropFeedback onResizeBegin(@NonNull INode child, @NonNull INode parent, @Nullable SegmentType horizontalEdge, + @Nullable SegmentType verticalEdge, @Nullable Object childView, @Nullable Object parentView) { return null; } @Override - public void onResizeUpdate(DropFeedback feedback, INode child, INode parent, Rect newBounds, + public void onResizeUpdate(@Nullable DropFeedback feedback, @NonNull INode child, @NonNull INode parent, @NonNull Rect newBounds, int modifierMask) { } @Override - public void onResizeEnd(DropFeedback feedback, INode child, final INode parent, - final Rect newBounds) { + public void onResizeEnd(@Nullable DropFeedback feedback, @NonNull INode child, final @NonNull INode parent, + final @NonNull Rect newBounds) { } } diff --git a/rule_api/src/com/android/ide/common/api/IClientRulesEngine.java b/rule_api/src/com/android/ide/common/api/IClientRulesEngine.java index ec28520..b9ea6cb 100644 --- a/rule_api/src/com/android/ide/common/api/IClientRulesEngine.java +++ b/rule_api/src/com/android/ide/common/api/IClientRulesEngine.java @@ -106,10 +106,10 @@ public interface IClientRulesEngine { /** * Returns a resource name validator for the current project * - * @return an {@link IValidator} for validating new resource name in the current + * @return an {@link IValidator} for validating a new resource name in the current * project */ - @NonNull + @Nullable IValidator getResourceValidator(); /** diff --git a/rule_api/src/com/android/ide/common/api/IMenuCallback.java b/rule_api/src/com/android/ide/common/api/IMenuCallback.java index fd100ee..2ff3f8d 100644 --- a/rule_api/src/com/android/ide/common/api/IMenuCallback.java +++ b/rule_api/src/com/android/ide/common/api/IMenuCallback.java @@ -49,4 +49,17 @@ public interface IMenuCallback { @NonNull List<? extends INode> selectedNodes, @Nullable String valueId, @Nullable Boolean newValue); + + /** Callback which does nothing */ + @NonNull + public static final IMenuCallback NONE = new IMenuCallback() { + @Override + public void action( + @NonNull RuleAction action, + @NonNull + List<? extends INode> selectedNodes, + @Nullable String valueId, + @Nullable Boolean newValue) { + } + }; } diff --git a/rule_api/src/com/android/ide/common/api/INode.java b/rule_api/src/com/android/ide/common/api/INode.java index d957419..b137699 100644 --- a/rule_api/src/com/android/ide/common/api/INode.java +++ b/rule_api/src/com/android/ide/common/api/INode.java @@ -180,7 +180,7 @@ public interface INode { * @param value It's value. Cannot be null. An empty value <em>removes</em> the attribute. * @return Whether the attribute was actually set or not. */ - boolean setAttribute(@Nullable String uri, @NonNull String localName, @NonNull String value); + boolean setAttribute(@Nullable String uri, @NonNull String localName, @Nullable String value); /** * Returns a given XML attribute. diff --git a/rule_api/src/com/android/ide/common/api/RuleAction.java b/rule_api/src/com/android/ide/common/api/RuleAction.java index f6c7e8c..489a3cc 100644 --- a/rule_api/src/com/android/ide/common/api/RuleAction.java +++ b/rule_api/src/com/android/ide/common/api/RuleAction.java @@ -448,9 +448,9 @@ public class RuleAction implements Comparable<RuleAction> { return mCallback; } - // Implements Comparable<MenuAciton> + // Implements Comparable<MenuAction> @Override - public int compareTo(@NonNull RuleAction other) { + public int compareTo(RuleAction other) { if (mSortPriority != other.mSortPriority) { return mSortPriority - other.mSortPriority; } @@ -468,7 +468,7 @@ public class RuleAction implements Comparable<RuleAction> { public static class Separator extends RuleAction { /** Construct using the factory {@link #createSeparator(int)} */ private Separator(int sortPriority, boolean supportsMultipleNodes) { - super("_separator", "", null, sortPriority, //$NON-NLS-1$ //$NON-NLS-2$ + super("_separator", "", IMenuCallback.NONE, sortPriority, //$NON-NLS-1$ //$NON-NLS-2$ supportsMultipleNodes); } } @@ -689,13 +689,13 @@ public class RuleAction implements Comparable<RuleAction> { } @Override - public List<String> getIds() { + public @NonNull List<String> getIds() { ensureInitialized(); return mIds; } @Override - public List<String> getTitles() { + public @NonNull List<String> getTitles() { ensureInitialized(); return mTitles; } diff --git a/rule_api/src/com/android/ide/common/api/Segment.java b/rule_api/src/com/android/ide/common/api/Segment.java index 9f03286..d31d9f8 100644 --- a/rule_api/src/com/android/ide/common/api/Segment.java +++ b/rule_api/src/com/android/ide/common/api/Segment.java @@ -51,7 +51,7 @@ public class Segment { public final MarginType marginType; /** The node that contains this edge */ - @NonNull + @Nullable public final INode node; /** @@ -61,7 +61,7 @@ public class Segment { @Nullable public final String id; - public Segment(int at, int from, int to, @NonNull INode node, @Nullable String id, + public Segment(int at, int from, int to, @Nullable INode node, @Nullable String id, @NonNull SegmentType edgeType, @NonNull MarginType marginType) { this.at = at; this.from = from; diff --git a/rule_api/src/com/android/ide/common/api/SegmentType.java b/rule_api/src/com/android/ide/common/api/SegmentType.java index 25635c7..9da248a 100644 --- a/rule_api/src/com/android/ide/common/api/SegmentType.java +++ b/rule_api/src/com/android/ide/common/api/SegmentType.java @@ -27,7 +27,22 @@ import com.google.common.annotations.Beta; */ @Beta public enum SegmentType { - LEFT, TOP, RIGHT, BOTTOM, BASELINE, CENTER_VERTICAL, CENTER_HORIZONTAL, UNKNOWN; + /** Segment is on the left edge */ + @NonNull LEFT, + /** Segment is on the top edge */ + @NonNull TOP, + /** Segment is on the right edge */ + @NonNull RIGHT, + /** Segment is on the bottom edge */ + @NonNull BOTTOM, + /** Segment is along the baseline */ + @NonNull BASELINE, + /** Segment is along the center vertically */ + @NonNull CENTER_VERTICAL, + /** Segment is along the center horizontally */ + @NonNull CENTER_HORIZONTAL, + /** Segment is on an unknown edge */ + @NonNull UNKNOWN; public boolean isHorizontal() { return this == TOP || this == BOTTOM || this == BASELINE || this == CENTER_HORIZONTAL; diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/build/JarListSanitizer.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/build/JarListSanitizer.java index fa7b00b..4d1dcdb 100644 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/build/JarListSanitizer.java +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/build/JarListSanitizer.java @@ -435,10 +435,11 @@ public class JarListSanitizer { */ private static String getSha1(File f) throws Sha1Exception { synchronized (sBuffer) { + FileInputStream fis = null; try { MessageDigest md = MessageDigest.getInstance("SHA-1"); - FileInputStream fis = new FileInputStream(f); + fis = new FileInputStream(f); while (true) { int length = fis.read(sBuffer); if (length > 0) { @@ -452,15 +453,27 @@ public class JarListSanitizer { } catch (Exception e) { throw new Sha1Exception(f, e); + } finally { + if (fis != null) { + try { + fis.close(); + } catch (IOException e) { + // ignore + } + } } } } private static String byteArray2Hex(final byte[] hash) { Formatter formatter = new Formatter(); - for (byte b : hash) { - formatter.format("%02x", b); + try { + for (byte b : hash) { + formatter.format("%02x", b); + } + return formatter.toString(); + } finally { + formatter.close(); } - return formatter.toString(); } } diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/avd/AvdManager.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/avd/AvdManager.java index dc19287..768a835 100644 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/avd/AvdManager.java +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/avd/AvdManager.java @@ -16,6 +16,7 @@ package com.android.sdklib.internal.avd; +import com.android.annotations.Nullable; import com.android.io.FileWrapper; import com.android.prefs.AndroidLocation; import com.android.prefs.AndroidLocation.AndroidLocationException; @@ -1404,14 +1405,14 @@ public class AvdManager { Wait.WAIT_FOR_READERS, new IProcessOutput() { @Override - public void out(String line) { + public void out(@Nullable String line) { if (line != null) { stdOutput.add(line); } } @Override - public void err(String line) { + public void err(@Nullable String line) { if (line != null) { errorOutput.add(line); } diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/avd/HardwareProperties.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/avd/HardwareProperties.java index c2c9bed..88495e0 100644 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/avd/HardwareProperties.java +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/avd/HardwareProperties.java @@ -121,9 +121,10 @@ public class HardwareProperties { * @return the map of (key,value) pairs, or null if the parsing failed. */ public static Map<String, HardwareProperty> parseHardwareDefinitions(File file, ISdkLog log) { + BufferedReader reader = null; try { FileInputStream fis = new FileInputStream(file); - BufferedReader reader = new BufferedReader(new InputStreamReader(fis)); + reader = new BufferedReader(new InputStreamReader(fis)); Map<String, HardwareProperty> map = new TreeMap<String, HardwareProperty>(); @@ -173,6 +174,14 @@ public class HardwareProperties { } catch (IOException e) { log.warning("Error parsing '%1$s': %2$s.", file.getAbsolutePath(), e.getMessage()); + } finally { + if (reader != null) { + try { + reader.close(); + } catch (IOException e) { + // ignore + } + } } return null; diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/build/KeystoreHelper.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/build/KeystoreHelper.java index af5b401..ba4ce8c 100644 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/build/KeystoreHelper.java +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/build/KeystoreHelper.java @@ -16,6 +16,7 @@ package com.android.sdklib.internal.build; +import com.android.annotations.Nullable; import com.android.sdklib.internal.build.DebugKeyProvider.IKeyGenOutput; import com.android.sdklib.internal.build.DebugKeyProvider.KeytoolException; import com.android.sdklib.util.GrabProcessOutput; @@ -111,7 +112,7 @@ public final class KeystoreHelper { Wait.WAIT_FOR_READERS, new IProcessOutput() { @Override - public void out(String line) { + public void out(@Nullable String line) { if (line != null) { if (output != null) { output.out(line); @@ -122,7 +123,7 @@ public final class KeystoreHelper { } @Override - public void err(String line) { + public void err(@Nullable String line) { if (line != null) { if (output != null) { output.err(line); diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectCreator.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectCreator.java index 721d165..f01c63a 100644 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectCreator.java +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectCreator.java @@ -929,8 +929,9 @@ public class ProjectCreator { private Matcher checkFileContainsRegexp(File file, String regexp) { Pattern p = Pattern.compile(regexp); + BufferedReader in = null; try { - BufferedReader in = new BufferedReader(new FileReader(file)); + in = new BufferedReader(new FileReader(file)); String line; while ((line = in.readLine()) != null) { @@ -943,6 +944,14 @@ public class ProjectCreator { in.close(); } catch (Exception e) { // ignore + } finally { + if (in != null) { + try { + in.close(); + } catch (IOException e) { + // ignore + } + } } return null; diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/archives/ArchiveInstaller.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/archives/ArchiveInstaller.java index 3addb31..c2e11cd 100755 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/archives/ArchiveInstaller.java +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/archives/ArchiveInstaller.java @@ -16,6 +16,7 @@ package com.android.sdklib.internal.repository.archives;
+import com.android.annotations.Nullable;
import com.android.annotations.VisibleForTesting;
import com.android.annotations.VisibleForTesting.Visibility;
import com.android.sdklib.SdkConstants;
@@ -609,14 +610,14 @@ public class ArchiveInstaller { Wait.WAIT_FOR_READERS,
new IProcessOutput() {
@Override
- public void out(String line) {
+ public void out(@Nullable String line) {
if (line != null) {
result.append(line).append("\n");
}
}
@Override
- public void err(String line) {
+ public void err(@Nullable String line) {
if (line != null) {
monitor.logError("[find_lock] Error: %1$s", line);
}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/packages/ToolPackage.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/packages/ToolPackage.java index 8ae469e..e2052c4 100755 --- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/packages/ToolPackage.java +++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/packages/ToolPackage.java @@ -16,6 +16,7 @@ package com.android.sdklib.internal.repository.packages;
+import com.android.annotations.Nullable;
import com.android.annotations.VisibleForTesting;
import com.android.annotations.VisibleForTesting.Visibility;
import com.android.sdklib.SdkConstants;
@@ -315,14 +316,14 @@ public class ToolPackage extends FullRevisionPackage implements IMinPlatformTool Wait.WAIT_FOR_PROCESS,
new IProcessOutput() {
@Override
- public void out(String line) {
+ public void out(@Nullable String line) {
if (line != null) {
monitor.log("[%1$s] %2$s", tag, line);
}
}
@Override
- public void err(String line) {
+ public void err(@Nullable String line) {
if (line != null) {
monitor.logError("[%1$s] Error: %2$s", tag, line);
}
diff --git a/sdkmanager/libs/sdklib/tests/src/com/android/sdklib/mock/MockLog.java b/sdkmanager/libs/sdklib/tests/src/com/android/sdklib/mock/MockLog.java index 24b120f..95a2693 100644 --- a/sdkmanager/libs/sdklib/tests/src/com/android/sdklib/mock/MockLog.java +++ b/sdkmanager/libs/sdklib/tests/src/com/android/sdklib/mock/MockLog.java @@ -32,7 +32,9 @@ public class MockLog implements ISdkLog { private ArrayList<String> mMessages = new ArrayList<String>(); private void add(String code, String format, Object... args) { - mMessages.add(new Formatter().format(code + format, args).toString()); + Formatter formatter = new Formatter(); + mMessages.add(formatter.format(code + format, args).toString()); + formatter.close(); } @Override diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java index daacf10..72488a3 100644 --- a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java +++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdSelector.java @@ -16,6 +16,7 @@ package com.android.sdkuilib.internal.widgets; +import com.android.annotations.Nullable; import com.android.prefs.AndroidLocation.AndroidLocationException; import com.android.sdklib.IAndroidTarget; import com.android.sdklib.ISdkLog; @@ -1080,6 +1081,7 @@ public final class AvdSelector { Formatter formatter = new Formatter(Locale.US); formatter.format("%.2f", scale); //$NON-NLS-1$ list.add(formatter.toString()); + formatter.close(); } // convert the list into an array for the call to exec. @@ -1112,14 +1114,14 @@ public final class AvdSelector { Wait.ASYNC, new IProcessOutput() { @Override - public void out(String line) { + public void out(@Nullable String line) { if (line != null) { filterStdOut(line); } } @Override - public void err(String line) { + public void err(@Nullable String line) { if (line != null) { filterStdErr(line); } diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdStartDialog.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdStartDialog.java index e2ac96b..63787f9 100644 --- a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdStartDialog.java +++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdStartDialog.java @@ -515,8 +515,9 @@ final class AvdStartDialog extends GridDialog { * @return true if both sizes where found. */ private boolean parseLayoutFile(File layoutFile) { + BufferedReader input = null; try { - BufferedReader input = new BufferedReader(new FileReader(layoutFile)); + input = new BufferedReader(new FileReader(layoutFile)); String line; while ((line = input.readLine()) != null) { @@ -563,6 +564,14 @@ final class AvdStartDialog extends GridDialog { // false is returned below. } catch (IOException e) { // ignore. + } finally { + if (input != null) { + try { + input.close(); + } catch (IOException e) { + // ignore + } + } } return false; diff --git a/templates/build.template b/templates/build.template index 1ab7ea2..aea57a2 100644 --- a/templates/build.template +++ b/templates/build.template @@ -28,6 +28,15 @@ --> <property file="ant.properties" /> + <!-- if sdk.dir was not set from one of the property file, then + get it from the ANDROID_HOME env var. + This must be done before we load project.properties since + the proguard config can use sdk.dir --> + <property environment="env" /> + <condition property="sdk.dir" value="${env.ANDROID_HOME}"> + <isset property="env.ANDROID_HOME" /> + </condition> + <!-- The project.properties file is created and updated by the 'android' tool, as well as ADT. @@ -39,13 +48,6 @@ application and should be checked into Version Control Systems. --> <loadproperties srcFile="project.properties" /> - <!-- if sdk.dir was not set from one of the property file, then - get it from the ANDROID_HOME env var. --> - <property environment="env" /> - <condition property="sdk.dir" value="${env.ANDROID_HOME}"> - <isset property="env.ANDROID_HOME" /> - </condition> - <!-- quick check on sdk.dir --> <fail message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable." diff --git a/testapps/customPropAnimTest/.classpath b/testapps/customPropAnimTest/.classpath new file mode 100644 index 0000000..a4763d1 --- /dev/null +++ b/testapps/customPropAnimTest/.classpath @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8"?> +<classpath> + <classpathentry kind="src" path="src"/> + <classpathentry kind="src" path="gen"/> + <classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/> + <classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/> + <classpathentry kind="output" path="bin/classes"/> +</classpath> diff --git a/testapps/customPropAnimTest/.project b/testapps/customPropAnimTest/.project new file mode 100644 index 0000000..0d12fe9 --- /dev/null +++ b/testapps/customPropAnimTest/.project @@ -0,0 +1,33 @@ +<?xml version="1.0" encoding="UTF-8"?> +<projectDescription> + <name>customPropAnimTest</name> + <comment></comment> + <projects> + </projects> + <buildSpec> + <buildCommand> + <name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>com.android.ide.eclipse.adt.PreCompilerBuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>org.eclipse.jdt.core.javabuilder</name> + <arguments> + </arguments> + </buildCommand> + <buildCommand> + <name>com.android.ide.eclipse.adt.ApkBuilder</name> + <arguments> + </arguments> + </buildCommand> + </buildSpec> + <natures> + <nature>com.android.ide.eclipse.adt.AndroidNature</nature> + <nature>org.eclipse.jdt.core.javanature</nature> + </natures> +</projectDescription> diff --git a/testapps/customPropAnimTest/AndroidManifest.xml b/testapps/customPropAnimTest/AndroidManifest.xml new file mode 100644 index 0000000..72c58d0 --- /dev/null +++ b/testapps/customPropAnimTest/AndroidManifest.xml @@ -0,0 +1,23 @@ +<?xml version="1.0" encoding="utf-8"?> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.custompropertyanimation" + android:versionCode="1" + android:versionName="1.0" > + + <uses-sdk android:minSdkVersion="15" /> + + <application + android:icon="@drawable/ic_launcher" + android:label="@string/app_name" > + <activity + android:name=".CustomPropertyAnimationActivity" + android:label="@string/app_name" > + <intent-filter> + <action android:name="android.intent.action.MAIN" /> + + <category android:name="android.intent.category.LAUNCHER" /> + </intent-filter> + </activity> + </application> + +</manifest>
\ No newline at end of file diff --git a/testapps/customPropAnimTest/build.xml b/testapps/customPropAnimTest/build.xml new file mode 100644 index 0000000..d6ee0bc --- /dev/null +++ b/testapps/customPropAnimTest/build.xml @@ -0,0 +1,90 @@ +<?xml version="1.0" encoding="UTF-8"?> +<project name="CustomPropertyAnimationActivity" default="help"> + + <!-- The local.properties file is created and updated by the 'android' tool. + It contains the path to the SDK. It should *NOT* be checked into + Version Control Systems. --> + <property file="local.properties" /> + + <!-- The ant.properties file can be created by you. It is only edited by the + 'android' tool to add properties to it. + This is the place to change some Ant specific build properties. + Here are some properties you may want to change/update: + + source.dir + The name of the source directory. Default is 'src'. + out.dir + The name of the output directory. Default is 'bin'. + + For other overridable properties, look at the beginning of the rules + files in the SDK, at tools/ant/build.xml + + Properties related to the SDK location or the project target should + be updated using the 'android' tool with the 'update' action. + + This file is an integral part of the build system for your + application and should be checked into Version Control Systems. + + --> + <property file="ant.properties" /> + + <!-- The project.properties file is created and updated by the 'android' + tool, as well as ADT. + + This contains project specific properties such as project target, and library + dependencies. Lower level build properties are stored in ant.properties + (or in .classpath for Eclipse projects). + + This file is an integral part of the build system for your + application and should be checked into Version Control Systems. --> + <loadproperties srcFile="project.properties" /> + + <!-- if sdk.dir was not set from one of the property file, then + get it from the ANDROID_HOME env var. --> + <property environment="env" /> + <condition property="sdk.dir" value="${env.ANDROID_HOME}"> + <isset property="env.ANDROID_HOME" /> + </condition> + + <!-- quick check on sdk.dir --> + <fail + message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable." + unless="sdk.dir" + /> + + <!-- + Import per project custom build rules if present at the root of the project. + This is the place to put custom intermediary targets such as: + -pre-build + -pre-compile + -post-compile (This is typically used for code obfuscation. + Compiled code location: ${out.classes.absolute.dir} + If this is not done in place, override ${out.dex.input.absolute.dir}) + -post-package + -post-build + -pre-clean + --> + <import file="custom_rules.xml" optional="true" /> + + <!-- Import the actual build file. + + To customize existing targets, there are two options: + - Customize only one target: + - copy/paste the target into this file, *before* the + <import> task. + - customize it to your needs. + - Customize the whole content of build.xml + - copy/paste the content of the rules files (minus the top node) + into this file, replacing the <import> task. + - customize to your needs. + + *********************** + ****** IMPORTANT ****** + *********************** + In all cases you must update the value of version-tag below to read 'custom' instead of an integer, + in order to avoid having your file be overridden by tools such as "android update project" + --> + <!-- version-tag: 1 --> + <import file="${sdk.dir}/tools/ant/build.xml" /> + +</project> diff --git a/testapps/customPropAnimTest/proguard-project.txt b/testapps/customPropAnimTest/proguard-project.txt new file mode 100644 index 0000000..f2fe155 --- /dev/null +++ b/testapps/customPropAnimTest/proguard-project.txt @@ -0,0 +1,20 @@ +# To enable ProGuard in your project, edit project.properties +# to define the proguard.config property as described in that file. +# +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in ${sdk.dir}/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the ProGuard +# include property in project.properties. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/testapps/customPropAnimTest/project.properties b/testapps/customPropAnimTest/project.properties new file mode 100644 index 0000000..1a88dc6 --- /dev/null +++ b/testapps/customPropAnimTest/project.properties @@ -0,0 +1,15 @@ +# This file is automatically generated by Android Tools. +# Do not modify this file -- YOUR CHANGES WILL BE ERASED! +# +# This file must be checked in Version Control Systems. +# +# To customize properties used by the Ant build system edit +# "ant.properties", and override values to adapt the script to your +# project structure. +# +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt + +# Project target. +target=android-15 + diff --git a/testapps/customPropAnimTest/res/drawable-hdpi/ic_launcher.png b/testapps/customPropAnimTest/res/drawable-hdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..96a442e --- /dev/null +++ b/testapps/customPropAnimTest/res/drawable-hdpi/ic_launcher.png diff --git a/testapps/customPropAnimTest/res/drawable-ldpi/ic_launcher.png b/testapps/customPropAnimTest/res/drawable-ldpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..9923872 --- /dev/null +++ b/testapps/customPropAnimTest/res/drawable-ldpi/ic_launcher.png diff --git a/testapps/customPropAnimTest/res/drawable-mdpi/ic_launcher.png b/testapps/customPropAnimTest/res/drawable-mdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..359047d --- /dev/null +++ b/testapps/customPropAnimTest/res/drawable-mdpi/ic_launcher.png diff --git a/testapps/customPropAnimTest/res/drawable-xhdpi/ic_launcher.png b/testapps/customPropAnimTest/res/drawable-xhdpi/ic_launcher.png Binary files differnew file mode 100644 index 0000000..71c6d76 --- /dev/null +++ b/testapps/customPropAnimTest/res/drawable-xhdpi/ic_launcher.png diff --git a/testapps/customPropAnimTest/res/layout/main.xml b/testapps/customPropAnimTest/res/layout/main.xml new file mode 100644 index 0000000..40f9f1a --- /dev/null +++ b/testapps/customPropAnimTest/res/layout/main.xml @@ -0,0 +1,8 @@ +<?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" + android:orientation="vertical" + android:id="@+id/container"> + +</LinearLayout>
\ No newline at end of file diff --git a/testapps/customPropAnimTest/res/values/strings.xml b/testapps/customPropAnimTest/res/values/strings.xml new file mode 100644 index 0000000..9c3c31b --- /dev/null +++ b/testapps/customPropAnimTest/res/values/strings.xml @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + + <string name="hello">Hello World, CustomPropertyAnimationActivity!</string> + <string name="app_name">CustomPropertyAnimation</string> + +</resources>
\ No newline at end of file diff --git a/testapps/customPropAnimTest/src/com/android/custompropertyanimation/CustomPropertyAnimationActivity.java b/testapps/customPropAnimTest/src/com/android/custompropertyanimation/CustomPropertyAnimationActivity.java new file mode 100644 index 0000000..b1b91b9 --- /dev/null +++ b/testapps/customPropAnimTest/src/com/android/custompropertyanimation/CustomPropertyAnimationActivity.java @@ -0,0 +1,22 @@ +package com.android.custompropertyanimation; + +import android.animation.ObjectAnimator; +import android.app.Activity; +import android.os.Bundle; +import android.widget.LinearLayout; + +public class CustomPropertyAnimationActivity extends Activity { + /** Called when the activity is first created. */ + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.main); + LinearLayout container = (LinearLayout) findViewById(R.id.container); + + MyView view = new MyView(this); + container.addView(view); + + ObjectAnimator anim = ObjectAnimator.ofFloat(view, "foo", 1); + anim.start(); + } +}
\ No newline at end of file diff --git a/testapps/customPropAnimTest/src/com/android/custompropertyanimation/MyView.java b/testapps/customPropAnimTest/src/com/android/custompropertyanimation/MyView.java new file mode 100644 index 0000000..e557fda --- /dev/null +++ b/testapps/customPropAnimTest/src/com/android/custompropertyanimation/MyView.java @@ -0,0 +1,24 @@ +package com.android.custompropertyanimation; + +import android.content.Context; +import android.view.View; + +public class MyView extends View { + + float mFoo = 0; + + public MyView(Context context) { + super(context); + } + + public void setFoo(float foo) { + System.out.println("foo = " + foo); + mFoo = foo; + } + + public float getFoo() { + System.out.println("getFoo() returning " + mFoo); + return mFoo; + } + +} diff --git a/testapps/customViewTest/libWithCustomView/build.xml b/testapps/customViewTest/libWithCustomView/build.xml index 772f422..7d9e032 100644 --- a/testapps/customViewTest/libWithCustomView/build.xml +++ b/testapps/customViewTest/libWithCustomView/build.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<project name="basicLibWithSupport" default="help"> +<project name="libWithCustomView" default="help"> <!-- The local.properties file is created and updated by the 'android' tool. It contains the path to the SDK. It should *NOT* be checked into @@ -39,27 +39,32 @@ application and should be checked into Version Control Systems. --> <loadproperties srcFile="project.properties" /> + <!-- if sdk.dir was not set from one of the property file, then + get it from the ANDROID_HOME env var. --> + <property environment="env" /> + <condition property="sdk.dir" value="${env.ANDROID_HOME}"> + <isset property="env.ANDROID_HOME" /> + </condition> + <!-- quick check on sdk.dir --> <fail - message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through an env var" + message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable." unless="sdk.dir" /> - -<!-- extension targets. Uncomment the ones where you want to do custom work - in between standard targets --> -<!-- - <target name="-pre-build"> - </target> - <target name="-pre-compile"> - </target> - - /* This is typically used for code obfuscation. - Compiled code location: ${out.classes.absolute.dir} - If this is not done in place, override ${out.dex.input.absolute.dir} */ - <target name="-post-compile"> - </target> ---> + <!-- + Import per project custom build rules if present at the root of the project. + This is the place to put custom intermediary targets such as: + -pre-build + -pre-compile + -post-compile (This is typically used for code obfuscation. + Compiled code location: ${out.classes.absolute.dir} + If this is not done in place, override ${out.dex.input.absolute.dir}) + -post-package + -post-build + -pre-clean + --> + <import file="custom_rules.xml" optional="true" /> <!-- Import the actual build file. diff --git a/testapps/customViewTest/mainProject/build.xml b/testapps/customViewTest/mainProject/build.xml index f3a3d91..2f98bb5 100644 --- a/testapps/customViewTest/mainProject/build.xml +++ b/testapps/customViewTest/mainProject/build.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<project name="basicProjectWithSupport" default="help"> +<project name="customViewTest-mainProject" default="help"> <!-- The local.properties file is created and updated by the 'android' tool. It contains the path to the SDK. It should *NOT* be checked into @@ -39,27 +39,32 @@ application and should be checked into Version Control Systems. --> <loadproperties srcFile="project.properties" /> + <!-- if sdk.dir was not set from one of the property file, then + get it from the ANDROID_HOME env var. --> + <property environment="env" /> + <condition property="sdk.dir" value="${env.ANDROID_HOME}"> + <isset property="env.ANDROID_HOME" /> + </condition> + <!-- quick check on sdk.dir --> <fail - message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through an env var" + message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable." unless="sdk.dir" /> - -<!-- extension targets. Uncomment the ones where you want to do custom work - in between standard targets --> -<!-- - <target name="-pre-build"> - </target> - <target name="-pre-compile"> - </target> - - /* This is typically used for code obfuscation. - Compiled code location: ${out.classes.absolute.dir} - If this is not done in place, override ${out.dex.input.absolute.dir} */ - <target name="-post-compile"> - </target> ---> + <!-- + Import per project custom build rules if present at the root of the project. + This is the place to put custom intermediary targets such as: + -pre-build + -pre-compile + -post-compile (This is typically used for code obfuscation. + Compiled code location: ${out.classes.absolute.dir} + If this is not done in place, override ${out.dex.input.absolute.dir}) + -post-package + -post-build + -pre-clean + --> + <import file="custom_rules.xml" optional="true" /> <!-- Import the actual build file. diff --git a/testapps/customViewTest/mainProject/proguard.cfg b/testapps/customViewTest/mainProject/proguard.cfg deleted file mode 100644 index b1cdf17..0000000 --- a/testapps/customViewTest/mainProject/proguard.cfg +++ /dev/null @@ -1,40 +0,0 @@ --optimizationpasses 5 --dontusemixedcaseclassnames --dontskipnonpubliclibraryclasses --dontpreverify --verbose --optimizations !code/simplification/arithmetic,!field/*,!class/merging/* - --keep public class * extends android.app.Activity --keep public class * extends android.app.Application --keep public class * extends android.app.Service --keep public class * extends android.content.BroadcastReceiver --keep public class * extends android.content.ContentProvider --keep public class * extends android.app.backup.BackupAgentHelper --keep public class * extends android.preference.Preference --keep public class com.android.vending.licensing.ILicensingService - --keepclasseswithmembernames class * { - native <methods>; -} - --keepclasseswithmembers class * { - public <init>(android.content.Context, android.util.AttributeSet); -} - --keepclasseswithmembers class * { - public <init>(android.content.Context, android.util.AttributeSet, int); -} - --keepclassmembers class * extends android.app.Activity { - public void *(android.view.View); -} - --keepclassmembers enum * { - public static **[] values(); - public static ** valueOf(java.lang.String); -} - --keep class * implements android.os.Parcelable { - public static final android.os.Parcelable$Creator *; -} diff --git a/testapps/customViewTest/mainProject/project.properties b/testapps/customViewTest/mainProject/project.properties index b80c0cf..21d68c5 100644 --- a/testapps/customViewTest/mainProject/project.properties +++ b/testapps/customViewTest/mainProject/project.properties @@ -10,3 +10,6 @@ # Project target. target=android-15 android.library.reference.1=../libWithCustomView + +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt diff --git a/testapps/customViewTest/mainProject/res/values/strings.xml b/testapps/customViewTest/mainProject/res/values/strings.xml index 3fa203a..e86ca41 100644 --- a/testapps/customViewTest/mainProject/res/values/strings.xml +++ b/testapps/customViewTest/mainProject/res/values/strings.xml @@ -1,4 +1,4 @@ <?xml version="1.0" encoding="utf-8"?> <resources> - <string name="app_name">MyActivity</string> + <string name="app_name">customViewTest</string> </resources> diff --git a/testapps/libsAndJarTest/app/build.xml b/testapps/libsAndJarTest/app/build.xml index 1160e8a..c084512 100644 --- a/testapps/libsAndJarTest/app/build.xml +++ b/testapps/libsAndJarTest/app/build.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<project name="app" default="help"> +<project name="libsAndJarTest-app" default="help"> <!-- The local.properties file is created and updated by the 'android' tool. It contains the path to the SDK. It should *NOT* be checked into @@ -28,6 +28,13 @@ --> <property file="ant.properties" /> + <!-- if sdk.dir was not set from one of the property file, then + get it from the ANDROID_HOME env var. --> + <property environment="env" /> + <condition property="sdk.dir" value="${env.ANDROID_HOME}"> + <isset property="env.ANDROID_HOME" /> + </condition> + <!-- The project.properties file is created and updated by the 'android' tool, as well as ADT. @@ -41,7 +48,7 @@ <!-- quick check on sdk.dir --> <fail - message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through an env var" + message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable." unless="sdk.dir" /> diff --git a/testapps/libsAndJarTest/app/project.properties b/testapps/libsAndJarTest/app/project.properties index 4fe0502..9df4221 100644 --- a/testapps/libsAndJarTest/app/project.properties +++ b/testapps/libsAndJarTest/app/project.properties @@ -7,9 +7,9 @@ # "ant.properties", and override values to adapt the script to your # project structure. # -# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): -proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt - # Project target. target=android-15 android.library.reference.1=../lib1 + +# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home): +proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt diff --git a/testapps/libsAndJarTest/lib1/build.xml b/testapps/libsAndJarTest/lib1/build.xml index 2a15ae6..ed25521 100644 --- a/testapps/libsAndJarTest/lib1/build.xml +++ b/testapps/libsAndJarTest/lib1/build.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<project name="lib1" default="help"> +<project name="libsAndJarTest-lib1" default="help"> <!-- The local.properties file is created and updated by the 'android' tool. It contains the path to the SDK. It should *NOT* be checked into @@ -39,9 +39,16 @@ application and should be checked into Version Control Systems. --> <loadproperties srcFile="project.properties" /> + <!-- if sdk.dir was not set from one of the property file, then + get it from the ANDROID_HOME env var. --> + <property environment="env" /> + <condition property="sdk.dir" value="${env.ANDROID_HOME}"> + <isset property="env.ANDROID_HOME" /> + </condition> + <!-- quick check on sdk.dir --> <fail - message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through an env var" + message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable." unless="sdk.dir" /> diff --git a/testapps/libsAndJarTest/lib2/build.xml b/testapps/libsAndJarTest/lib2/build.xml index 3d36fda..4f351c8 100644 --- a/testapps/libsAndJarTest/lib2/build.xml +++ b/testapps/libsAndJarTest/lib2/build.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<project name="lib2" default="help"> +<project name="libsAndJarTest-lib2" default="help"> <!-- The local.properties file is created and updated by the 'android' tool. It contains the path to the SDK. It should *NOT* be checked into @@ -39,9 +39,16 @@ application and should be checked into Version Control Systems. --> <loadproperties srcFile="project.properties" /> + <!-- if sdk.dir was not set from one of the property file, then + get it from the ANDROID_HOME env var. --> + <property environment="env" /> + <condition property="sdk.dir" value="${env.ANDROID_HOME}"> + <isset property="env.ANDROID_HOME" /> + </condition> + <!-- quick check on sdk.dir --> <fail - message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through an env var" + message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable." unless="sdk.dir" /> diff --git a/traceview/src/com/android/traceview/DmTraceReader.java b/traceview/src/com/android/traceview/DmTraceReader.java index 285897b..b49d75e 100644 --- a/traceview/src/com/android/traceview/DmTraceReader.java +++ b/traceview/src/com/android/traceview/DmTraceReader.java @@ -103,12 +103,16 @@ public class DmTraceReader extends TraceReader { private MappedByteBuffer mapFile(String filename, long offset) throws IOException { MappedByteBuffer buffer = null; FileInputStream dataFile = new FileInputStream(filename); - File file = new File(filename); - FileChannel fc = dataFile.getChannel(); - buffer = fc.map(FileChannel.MapMode.READ_ONLY, offset, file.length() - offset); - buffer.order(ByteOrder.LITTLE_ENDIAN); + try { + File file = new File(filename); + FileChannel fc = dataFile.getChannel(); + buffer = fc.map(FileChannel.MapMode.READ_ONLY, offset, file.length() - offset); + buffer.order(ByteOrder.LITTLE_ENDIAN); - return buffer; + return buffer; + } finally { + dataFile.close(); // this *also* closes the associated channel, fc + } } private void readDataFileHeader(MappedByteBuffer buffer) { @@ -402,63 +406,68 @@ public class DmTraceReader extends TraceReader { static final int PARSE_OPTIONS = 4; long parseKeys() throws IOException { + long offset = 0; BufferedReader in = null; try { in = new BufferedReader(new InputStreamReader( new FileInputStream(mTraceFileName), "US-ASCII")); - } catch (FileNotFoundException ex) { - System.err.println(ex.getMessage()); - } - long offset = 0; - int mode = PARSE_VERSION; - String line = null; - while (true) { - line = in.readLine(); - if (line == null) { - throw new IOException("Key section does not have an *end marker"); - } - - // Calculate how much we have read from the file so far. The - // extra byte is for the line ending not included by readLine(). - offset += line.length() + 1; - if (line.startsWith("*")) { - if (line.equals("*version")) { - mode = PARSE_VERSION; - continue; - } - if (line.equals("*threads")) { - mode = PARSE_THREADS; - continue; + int mode = PARSE_VERSION; + String line = null; + while (true) { + line = in.readLine(); + if (line == null) { + throw new IOException("Key section does not have an *end marker"); } - if (line.equals("*methods")) { - mode = PARSE_METHODS; - continue; + + // Calculate how much we have read from the file so far. The + // extra byte is for the line ending not included by readLine(). + offset += line.length() + 1; + if (line.startsWith("*")) { + if (line.equals("*version")) { + mode = PARSE_VERSION; + continue; + } + if (line.equals("*threads")) { + mode = PARSE_THREADS; + continue; + } + if (line.equals("*methods")) { + mode = PARSE_METHODS; + continue; + } + if (line.equals("*end")) { + break; + } } - if (line.equals("*end")) { + switch (mode) { + case PARSE_VERSION: + mVersionNumber = Integer.decode(line); + mode = PARSE_OPTIONS; + break; + case PARSE_THREADS: + parseThread(line); + break; + case PARSE_METHODS: + parseMethod(line); + break; + case PARSE_OPTIONS: + parseOption(line); break; } } - switch (mode) { - case PARSE_VERSION: - mVersionNumber = Integer.decode(line); - mode = PARSE_OPTIONS; - break; - case PARSE_THREADS: - parseThread(line); - break; - case PARSE_METHODS: - parseMethod(line); - break; - case PARSE_OPTIONS: - parseOption(line); - break; + } catch (FileNotFoundException ex) { + System.err.println(ex.getMessage()); + } finally { + if (in != null) { + in.close(); } } if (mClockSource == null) { mClockSource = ClockSource.THREAD_CPU; } + return offset; } diff --git a/traceview/src/com/android/traceview/MainWindow.java b/traceview/src/com/android/traceview/MainWindow.java index 3414d84..ebab72b 100644 --- a/traceview/src/com/android/traceview/MainWindow.java +++ b/traceview/src/com/android/traceview/MainWindow.java @@ -146,20 +146,36 @@ public class MainWindow extends ApplicationWindow { // write into it. File temp = File.createTempFile(base, ".trace"); temp.deleteOnExit(); - FileChannel dstChannel = new FileOutputStream(temp).getChannel(); - // First copy the contents of the key file into our temp file. - FileChannel srcChannel = new FileInputStream(base + ".key").getChannel(); - long size = dstChannel.transferFrom(srcChannel, 0, srcChannel.size()); - srcChannel.close(); - - // Then concatenate the data file. - srcChannel = new FileInputStream(base + ".data").getChannel(); - dstChannel.transferFrom(srcChannel, size, srcChannel.size()); - - // Clean up. - srcChannel.close(); - dstChannel.close(); + FileOutputStream dstStream = null; + FileInputStream keyStream = null; + FileInputStream dataStream = null; + + try { + dstStream = new FileOutputStream(temp); + FileChannel dstChannel = dstStream.getChannel(); + + // First copy the contents of the key file into our temp file. + keyStream = new FileInputStream(base + ".key"); + FileChannel srcChannel = keyStream.getChannel(); + long size = dstChannel.transferFrom(srcChannel, 0, srcChannel.size()); + srcChannel.close(); + + // Then concatenate the data file. + dataStream = new FileInputStream(base + ".data"); + srcChannel = dataStream.getChannel(); + dstChannel.transferFrom(srcChannel, size, srcChannel.size()); + } finally { + if (dstStream != null) { + dstStream.close(); // also closes dstChannel + } + if (keyStream != null) { + keyStream.close(); // also closes srcChannel + } + if (dataStream != null) { + dataStream.close(); + } + } // Return the path of the temp file. return temp.getPath(); |