diff options
Diffstat (limited to 'tools/layoutlib/create')
46 files changed, 0 insertions, 6704 deletions
diff --git a/tools/layoutlib/create/.classpath b/tools/layoutlib/create/.classpath deleted file mode 100644 index dbc4cfd..0000000 --- a/tools/layoutlib/create/.classpath +++ /dev/null @@ -1,9 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<classpath> - <classpathentry kind="src" path="src"/> - <classpathentry excluding="mock_android/" kind="src" path="tests"/> - <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/> - <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/> - <classpathentry kind="var" path="ANDROID_SRC/prebuilts/tools/common/asm-tools/asm-4.0.jar"/> - <classpathentry kind="output" path="bin"/> -</classpath> diff --git a/tools/layoutlib/create/.project b/tools/layoutlib/create/.project deleted file mode 100644 index e100d17..0000000 --- a/tools/layoutlib/create/.project +++ /dev/null @@ -1,17 +0,0 @@ -<?xml version="1.0" encoding="UTF-8"?> -<projectDescription> - <name>layoutlib_create</name> - <comment></comment> - <projects> - </projects> - <buildSpec> - <buildCommand> - <name>org.eclipse.jdt.core.javabuilder</name> - <arguments> - </arguments> - </buildCommand> - </buildSpec> - <natures> - <nature>org.eclipse.jdt.core.javanature</nature> - </natures> -</projectDescription> diff --git a/tools/layoutlib/create/.settings/README.txt b/tools/layoutlib/create/.settings/README.txt deleted file mode 100644 index 9120b20..0000000 --- a/tools/layoutlib/create/.settings/README.txt +++ /dev/null @@ -1,2 +0,0 @@ -Copy this in eclipse project as a .settings folder at the root. -This ensure proper compilation compliance and warning/error levels.
\ No newline at end of file diff --git a/tools/layoutlib/create/.settings/org.eclipse.jdt.core.prefs b/tools/layoutlib/create/.settings/org.eclipse.jdt.core.prefs deleted file mode 100644 index 5381a0e..0000000 --- a/tools/layoutlib/create/.settings/org.eclipse.jdt.core.prefs +++ /dev/null @@ -1,93 +0,0 @@ -eclipse.preferences.version=1 -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.codegen.inlineJsrBytecode=enabled -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 -org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve -org.eclipse.jdt.core.compiler.compliance=1.6 -org.eclipse.jdt.core.compiler.debug.lineNumber=generate -org.eclipse.jdt.core.compiler.debug.localVariable=generate -org.eclipse.jdt.core.compiler.debug.sourceFile=generate -org.eclipse.jdt.core.compiler.problem.annotationSuperInterface=warning -org.eclipse.jdt.core.compiler.problem.assertIdentifier=error -org.eclipse.jdt.core.compiler.problem.autoboxing=ignore -org.eclipse.jdt.core.compiler.problem.comparingIdentical=warning -org.eclipse.jdt.core.compiler.problem.deadCode=warning -org.eclipse.jdt.core.compiler.problem.deprecation=warning -org.eclipse.jdt.core.compiler.problem.deprecationInDeprecatedCode=disabled -org.eclipse.jdt.core.compiler.problem.deprecationWhenOverridingDeprecatedMethod=disabled -org.eclipse.jdt.core.compiler.problem.discouragedReference=warning -org.eclipse.jdt.core.compiler.problem.emptyStatement=ignore -org.eclipse.jdt.core.compiler.problem.enumIdentifier=error -org.eclipse.jdt.core.compiler.problem.explicitlyClosedAutoCloseable=ignore -org.eclipse.jdt.core.compiler.problem.fallthroughCase=warning -org.eclipse.jdt.core.compiler.problem.fatalOptionalError=enabled -org.eclipse.jdt.core.compiler.problem.fieldHiding=warning -org.eclipse.jdt.core.compiler.problem.finalParameterBound=warning -org.eclipse.jdt.core.compiler.problem.finallyBlockNotCompletingNormally=warning -org.eclipse.jdt.core.compiler.problem.forbiddenReference=error -org.eclipse.jdt.core.compiler.problem.hiddenCatchBlock=warning -org.eclipse.jdt.core.compiler.problem.includeNullInfoFromAsserts=enabled -org.eclipse.jdt.core.compiler.problem.incompatibleNonInheritedInterfaceMethod=warning -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.missingDeprecatedAnnotation=warning -org.eclipse.jdt.core.compiler.problem.missingHashCodeMethod=warning -org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotation=error -org.eclipse.jdt.core.compiler.problem.missingOverrideAnnotationForInterfaceMethodImplementation=enabled -org.eclipse.jdt.core.compiler.problem.missingSerialVersion=warning -org.eclipse.jdt.core.compiler.problem.missingSynchronizedOnInheritedMethod=ignore -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.nullReference=error -org.eclipse.jdt.core.compiler.problem.nullSpecInsufficientInfo=warning -org.eclipse.jdt.core.compiler.problem.nullSpecViolation=error -org.eclipse.jdt.core.compiler.problem.overridingPackageDefaultMethod=warning -org.eclipse.jdt.core.compiler.problem.parameterAssignment=ignore -org.eclipse.jdt.core.compiler.problem.possibleAccidentalBooleanAssignment=warning -org.eclipse.jdt.core.compiler.problem.potentialNullReference=warning -org.eclipse.jdt.core.compiler.problem.potentialNullSpecViolation=error -org.eclipse.jdt.core.compiler.problem.potentiallyUnclosedCloseable=warning -org.eclipse.jdt.core.compiler.problem.rawTypeReference=warning -org.eclipse.jdt.core.compiler.problem.redundantNullAnnotation=warning -org.eclipse.jdt.core.compiler.problem.redundantNullCheck=ignore -org.eclipse.jdt.core.compiler.problem.redundantSpecificationOfTypeArguments=ignore -org.eclipse.jdt.core.compiler.problem.redundantSuperinterface=warning -org.eclipse.jdt.core.compiler.problem.reportMethodCanBePotentiallyStatic=ignore -org.eclipse.jdt.core.compiler.problem.reportMethodCanBeStatic=ignore -org.eclipse.jdt.core.compiler.problem.specialParameterHidingField=disabled -org.eclipse.jdt.core.compiler.problem.staticAccessReceiver=warning -org.eclipse.jdt.core.compiler.problem.suppressOptionalErrors=disabled -org.eclipse.jdt.core.compiler.problem.suppressWarnings=enabled -org.eclipse.jdt.core.compiler.problem.syntheticAccessEmulation=ignore -org.eclipse.jdt.core.compiler.problem.typeParameterHiding=warning -org.eclipse.jdt.core.compiler.problem.unavoidableGenericTypeProblems=disabled -org.eclipse.jdt.core.compiler.problem.uncheckedTypeOperation=warning -org.eclipse.jdt.core.compiler.problem.unclosedCloseable=error -org.eclipse.jdt.core.compiler.problem.undocumentedEmptyBlock=ignore -org.eclipse.jdt.core.compiler.problem.unhandledWarningToken=warning -org.eclipse.jdt.core.compiler.problem.unnecessaryElse=ignore -org.eclipse.jdt.core.compiler.problem.unnecessaryTypeCheck=warning -org.eclipse.jdt.core.compiler.problem.unqualifiedFieldAccess=ignore -org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownException=warning -org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionExemptExceptionAndThrowable=enabled -org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionIncludeDocCommentReference=enabled -org.eclipse.jdt.core.compiler.problem.unusedDeclaredThrownExceptionWhenOverriding=disabled -org.eclipse.jdt.core.compiler.problem.unusedImport=warning -org.eclipse.jdt.core.compiler.problem.unusedLabel=warning -org.eclipse.jdt.core.compiler.problem.unusedLocal=warning -org.eclipse.jdt.core.compiler.problem.unusedObjectAllocation=warning -org.eclipse.jdt.core.compiler.problem.unusedParameter=ignore -org.eclipse.jdt.core.compiler.problem.unusedParameterIncludeDocCommentReference=enabled -org.eclipse.jdt.core.compiler.problem.unusedParameterWhenImplementingAbstract=disabled -org.eclipse.jdt.core.compiler.problem.unusedParameterWhenOverridingConcrete=disabled -org.eclipse.jdt.core.compiler.problem.unusedPrivateMember=warning -org.eclipse.jdt.core.compiler.problem.unusedWarningToken=warning -org.eclipse.jdt.core.compiler.problem.varargsArgumentNeedCast=warning -org.eclipse.jdt.core.compiler.source=1.6 diff --git a/tools/layoutlib/create/Android.mk b/tools/layoutlib/create/Android.mk deleted file mode 100644 index 9bd48ab..0000000 --- a/tools/layoutlib/create/Android.mk +++ /dev/null @@ -1,28 +0,0 @@ -# -# Copyright (C) 2008 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. -# -LOCAL_PATH := $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES := $(call all-java-files-under,src) - -LOCAL_JAR_MANIFEST := manifest.txt -LOCAL_STATIC_JAVA_LIBRARIES := \ - asm-4.0 - -LOCAL_MODULE := layoutlib_create - -include $(BUILD_HOST_JAVA_LIBRARY) - diff --git a/tools/layoutlib/create/README.txt b/tools/layoutlib/create/README.txt deleted file mode 100644 index 894611b..0000000 --- a/tools/layoutlib/create/README.txt +++ /dev/null @@ -1,240 +0,0 @@ -# Copyright (C) 2008 The Android Open Source Project - - -- Description - ---------------- - -Layoutlib_create generates a JAR library used by the Eclipse graphical layout editor -to perform layout. - - -- Usage - ---------- - - ./layoutlib_create path/to/android.jar destination.jar - - -- Design Overview - -------------------- - -Layoutlib_create uses the "android.jar" containing all the Java code used by Android -as generated by the Android build, right before the classes are converted to a DEX format. - -The Android JAR can't be used directly in Eclipse: -- it contains references to native code (which we want to avoid in Eclipse), -- some classes need to be overridden, for example all the drawing code that is - replaced by Java 2D calls in Eclipse. -- some of the classes that need to be changed are final and/or we need access - to their private internal state. - -Consequently this tool: -- parses the input JAR, -- modifies some of the classes directly using some bytecode manipulation, -- filters some packages and removes those we don't want in the output JAR, -- injects some new classes, -- generates a modified JAR file that is suitable for the Android plugin - for Eclipse to perform rendering. - -The ASM library is used to do the bytecode modification using its visitor pattern API. - -The layoutlib_create is *NOT* generic. There is no configuration file. Instead all the -configuration is done in the main() method and the CreateInfo structure is expected to -change with the Android platform as new classes are added, changed or removed. - -The resulting JAR is used by layoutlib_bridge (a.k.a. "the bridge"), also part of the -platform, that provides all the necessary missing implementation for rendering graphics -in Eclipse. - - - -- Implementation Notes - ------------------------- - -The tool works in two phases: -- first analyze the input jar (AsmAnalyzer class) -- then generate the output jar (AsmGenerator class), - - -- Analyzer ----------- - -The goal of the analyzer is to create a graph of all the classes from the input JAR -with their dependencies and then only keep the ones we want. - -To do that, the analyzer is created with a list of base classes to keep -- everything -that derives from these is kept. Currently the one such class is android.view.View: -since we want to render layouts, anything that is sort of a view needs to be kept. - -The analyzer is also given a list of class names to keep in the output. -This is done using shell-like glob patterns that filter on the fully-qualified -class names, for example "android.*.R**" ("*" does not matches dots whilst "**" does, -and "." and "$" are interpreted as-is). -In practice we almost but not quite request the inclusion of full packages. - -With this information, the analyzer parses the input zip to find all the classes. -All classes deriving from the requested bases classes are kept. -All classes which name matched the glob pattern are kept. -The analysis then finds all the dependencies of the classes that are to be kept -using an ASM visitor on the class, the field types, the method types and annotations types. -Classes that belong to the current JRE are excluded. - -The output of the analyzer is a set of ASM ClassReader instances which are then -fed to the generator. - - -- Generator ------------ - -The generator is constructed from a CreateInfo struct that acts as a config file -and lists: -- the classes to inject in the output JAR -- these classes are directly implemented - in layoutlib_create and will be used to interface with the renderer in Eclipse. -- specific methods to override (see method stubs details below). -- specific methods for which to delegate calls. -- specific methods to remove based on their return type. -- specific classes to rename. - -Each of these are specific strategies we use to be able to modify the Android code -to fit within the Eclipse renderer. These strategies are explained beow. - -The core method of the generator is transform(): it takes an input ASM ClassReader -and modifies it to produce a byte array suitable for the final JAR file. - -The first step of the transformation is changing the name of the class in case -we requested the class to be renamed. This uses the RenameClassAdapter to also rename -all inner classes and references in methods and types. Note that other classes are -not transformed and keep referencing the original name. - -The TransformClassAdapter is then used to process the potentially renamed class. -All protected or private classes are market as public. -All classes are made non-final. -Interfaces are left as-is. - -If a method has a return type that must be erased, the whole method is skipped. -Methods are also changed from protected/private to public. -The code of the methods is then kept as-is, except for native methods which are -replaced by a stub. Methods that are to be overridden are also replaced by a stub. - -The transformed class is then fed through the DelegateClassAdapter to implement -method delegates. - -Finally fields are also visited and changed from protected/private to public. - - -- Method stubs --------------- - -As indicated above, all native and overridden methods are replaced by a stub. -We don't have the code to replace with in layoutlib_create. -Instead the StubMethodAdapter replaces the code of the method by a call to -OverrideMethod.invokeX(). When using the final JAR, the bridge can register -listeners from these overridden method calls based on the method signatures. - -The listeners are currently pretty basic: we only pass the signature of the -method being called, its caller object and a flag indicating whether the -method was native. We do not currently provide the parameters. The listener -can however specify the return value of the overridden method. - -This strategy is now obsolete and replaced by the method delegates. - - -- Strategies ------------- - -We currently have 4 strategies to deal with overriding the rendering code -and make it run in Eclipse. Most of these strategies are implemented hand-in-hand -by the bridge (which runs in Eclipse) and the generator. - - -1- Class Injection - -This is the easiest: we currently inject 4 classes, namely: -- OverrideMethod and its associated MethodListener and MethodAdapter are used - to intercept calls to some specific methods that are stubbed out and change - their return value. -- CreateInfo class, which configured the generator. Not used yet, but could - in theory help us track what the generator changed. - - -2- Overriding methods - -As explained earlier, the creator doesn't have any replacement code for -methods to override. Instead it removes the original code and replaces it -by a call to a specific OveriddeMethod.invokeX(). The bridge then registers -a listener on the method signature and can provide an implementation. - -This strategy is now obsolete and replaced by the method delegates. -See strategy 5 below. - - -3- Renaming classes - -This simply changes the name of a class in its definition, as well as all its -references in internal inner classes and methods. -Calls from other classes are not modified -- they keep referencing the original -class name. This allows the bridge to literally replace an implementation. - -An example will make this easier: android.graphics.Paint is the main drawing -class that we need to replace. To do so, the generator renames Paint to _original_Paint. -Later the bridge provides its own replacement version of Paint which will be used -by the rest of the Android stack. The replacement version of Paint can still use -(either by inheritance or delegation) all the original non-native code of _original_Paint -if it so desires. - -Some of the Android classes are basically wrappers over native objects and since -we don't have the native code in Eclipse, we need to provide a full alternate -implementation. Sub-classing doesn't work as some native methods are static and -we don't control object creation. - -This won't rename/replace the inner static methods of a given class. - - -4- Method erasure based on return type - -This is mostly an implementation detail of the bridge: in the Paint class -mentioned above, some inner static classes are used to pass around -attributes (e.g. FontMetrics, or the Style enum) and all the original implementation -is native. - -In this case we have a strategy that tells the generator that anything returning, for -example, the inner class Paint$Style in the Paint class should be discarded and the -bridge will provide its own implementation. - - -5- Method Delegates - -This strategy is used to override method implementations. -Given a method SomeClass.MethodName(), 1 or 2 methods are generated: -a- A copy of the original method named SomeClass.MethodName_Original(). - The content is the original method as-is from the reader. - This step is omitted if the method is native, since it has no Java implementation. -b- A brand new implementation of SomeClass.MethodName() which calls to a - non-existing static method named SomeClass_Delegate.MethodName(). - The implementation of this 'delegate' method is done in layoutlib_brigde. - -The delegate method is a static method. -If the original method is non-static, the delegate method receives the original 'this' -as its first argument. If the original method is an inner non-static method, it also -receives the inner 'this' as the second argument. - - - -- References - --------------- - - -The JVM Specification 2nd edition: - http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html - -Understanding bytecode: - http://www.ibm.com/developerworks/ibm/library/it-haggar_bytecode/ - -Bytecode opcode list: - http://en.wikipedia.org/wiki/Java_bytecode_instruction_listings - -ASM user guide: - http://download.forge.objectweb.org/asm/asm-guide.pdf - - --- -end diff --git a/tools/layoutlib/create/manifest.txt b/tools/layoutlib/create/manifest.txt deleted file mode 100644 index 238e7f9..0000000 --- a/tools/layoutlib/create/manifest.txt +++ /dev/null @@ -1 +0,0 @@ -Main-Class: com.android.tools.layoutlib.create.Main diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/annotations/LayoutlibDelegate.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/annotations/LayoutlibDelegate.java deleted file mode 100644 index 9a48ea6..0000000 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/annotations/LayoutlibDelegate.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2010 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.layoutlib.annotations; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Denotes a method that has been converted to a delegate by layoutlib_create. - */ -@Retention(RetentionPolicy.RUNTIME) -public @interface LayoutlibDelegate { -} diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/annotations/Nullable.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/annotations/Nullable.java deleted file mode 100644 index 0689c92..0000000 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/annotations/Nullable.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (C) 2010 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.layoutlib.annotations; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Denotes a parameter or field can be null. - * <p/> - * When decorating a method call parameter, this denotes the parameter can - * legitimately be null and the method will gracefully deal with it. Typically used - * on optional parameters. - * <p/> - * When decorating a method, this denotes the method might legitimately return null. - * <p/> - * This is a marker annotation and it has no specific attributes. - */ -@Retention(RetentionPolicy.SOURCE) -public @interface Nullable { -} diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/annotations/VisibleForTesting.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/annotations/VisibleForTesting.java deleted file mode 100644 index e4e016b..0000000 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/annotations/VisibleForTesting.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2010 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.layoutlib.annotations; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Denotes that the class, method or field has its visibility relaxed so - * that unit tests can access it. - * <p/> - * The <code>visibility</code> argument can be used to specific what the original - * visibility should have been if it had not been made public or package-private for testing. - * The default is to consider the element private. - */ -@Retention(RetentionPolicy.SOURCE) -public @interface VisibleForTesting { - /** - * Intended visibility if the element had not been made public or package-private for - * testing. - */ - enum Visibility { - /** The element should be considered protected. */ - PROTECTED, - /** The element should be considered package-private. */ - PACKAGE, - /** The element should be considered private. */ - PRIVATE - } - - /** - * Intended visibility if the element had not been made public or package-private for testing. - * If not specified, one should assume the element originally intended to be private. - */ - Visibility visibility() default Visibility.PRIVATE; -} diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java deleted file mode 100644 index 412695f..0000000 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmAnalyzer.java +++ /dev/null @@ -1,845 +0,0 @@ -/* - * Copyright (C) 2008 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.layoutlib.create; - -import org.objectweb.asm.AnnotationVisitor; -import org.objectweb.asm.Attribute; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.FieldVisitor; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; -import org.objectweb.asm.signature.SignatureReader; -import org.objectweb.asm.signature.SignatureVisitor; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.TreeMap; -import java.util.regex.Pattern; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -/** - * Analyzes the input JAR using the ASM java bytecode manipulation library - * to list the desired classes and their dependencies. - */ -public class AsmAnalyzer { - - // Note: a bunch of stuff has package-level access for unit tests. Consider it private. - - /** Output logger. */ - private final Log mLog; - /** The input source JAR to parse. */ - private final List<String> mOsSourceJar; - /** The generator to fill with the class list and dependency list. */ - private final AsmGenerator mGen; - /** Keep all classes that derive from these one (these included). */ - private final String[] mDeriveFrom; - /** Glob patterns of classes to keep, e.g. "com.foo.*" */ - private final String[] mIncludeGlobs; - - /** - * Creates a new analyzer. - * - * @param log The log output. - * @param osJarPath The input source JARs to parse. - * @param gen The generator to fill with the class list and dependency list. - * @param deriveFrom Keep all classes that derive from these one (these included). - * @param includeGlobs Glob patterns of classes to keep, e.g. "com.foo.*" - * ("*" does not matches dots whilst "**" does, "." and "$" are interpreted as-is) - */ - public AsmAnalyzer(Log log, List<String> osJarPath, AsmGenerator gen, - String[] deriveFrom, String[] includeGlobs) { - mLog = log; - mGen = gen; - mOsSourceJar = osJarPath != null ? osJarPath : new ArrayList<String>(); - mDeriveFrom = deriveFrom != null ? deriveFrom : new String[0]; - mIncludeGlobs = includeGlobs != null ? includeGlobs : new String[0]; - } - - /** - * Starts the analysis using parameters from the constructor. - * Fills the generator with classes & dependencies found. - */ - public void analyze() throws IOException, LogAbortException { - - AsmAnalyzer visitor = this; - - Map<String, ClassReader> zipClasses = parseZip(mOsSourceJar); - mLog.info("Found %d classes in input JAR%s.", zipClasses.size(), - mOsSourceJar.size() > 1 ? "s" : ""); - - Map<String, ClassReader> found = findIncludes(zipClasses); - Map<String, ClassReader> deps = findDeps(zipClasses, found); - - if (mGen != null) { - mGen.setKeep(found); - mGen.setDeps(deps); - } - } - - /** - * Parses a JAR file and returns a list of all classes founds using a map - * class name => ASM ClassReader. Class names are in the form "android.view.View". - */ - Map<String,ClassReader> parseZip(List<String> jarPathList) throws IOException { - TreeMap<String, ClassReader> classes = new TreeMap<String, ClassReader>(); - - for (String jarPath : jarPathList) { - ZipFile zip = new ZipFile(jarPath); - Enumeration<? extends ZipEntry> entries = zip.entries(); - ZipEntry entry; - while (entries.hasMoreElements()) { - entry = entries.nextElement(); - if (entry.getName().endsWith(".class")) { - ClassReader cr = new ClassReader(zip.getInputStream(entry)); - String className = classReaderToClassName(cr); - classes.put(className, cr); - } - } - } - - return classes; - } - - /** - * Utility that returns the fully qualified binary class name for a ClassReader. - * E.g. it returns something like android.view.View. - */ - static String classReaderToClassName(ClassReader classReader) { - if (classReader == null) { - return null; - } else { - return classReader.getClassName().replace('/', '.'); - } - } - - /** - * Utility that returns the fully qualified binary class name from a path-like FQCN. - * E.g. it returns android.view.View from android/view/View. - */ - static String internalToBinaryClassName(String className) { - if (className == null) { - return null; - } else { - return className.replace('/', '.'); - } - } - - /** - * Process the "includes" arrays. - * <p/> - * This updates the in_out_found map. - */ - Map<String, ClassReader> findIncludes(Map<String, ClassReader> zipClasses) - throws LogAbortException { - TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>(); - - mLog.debug("Find classes to include."); - - for (String s : mIncludeGlobs) { - findGlobs(s, zipClasses, found); - } - for (String s : mDeriveFrom) { - findClassesDerivingFrom(s, zipClasses, found); - } - - return found; - } - - - /** - * Uses ASM to find the class reader for the given FQCN class name. - * If found, insert it in the in_out_found map. - * Returns the class reader object. - */ - ClassReader findClass(String className, Map<String, ClassReader> zipClasses, - Map<String, ClassReader> inOutFound) throws LogAbortException { - ClassReader classReader = zipClasses.get(className); - if (classReader == null) { - throw new LogAbortException("Class %s not found by ASM in %s", - className, mOsSourceJar); - } - - inOutFound.put(className, classReader); - return classReader; - } - - /** - * Insert in the inOutFound map all classes found in zipClasses that match the - * given glob pattern. - * <p/> - * The glob pattern is not a regexp. It only accepts the "*" keyword to mean - * "anything but a period". The "." and "$" characters match themselves. - * The "**" keyword means everything including ".". - * <p/> - * Examples: - * <ul> - * <li>com.foo.* matches all classes in the package com.foo but NOT sub-packages. - * <li>com.foo*.*$Event matches all internal Event classes in a com.foo*.* class. - * </ul> - */ - void findGlobs(String globPattern, Map<String, ClassReader> zipClasses, - Map<String, ClassReader> inOutFound) throws LogAbortException { - // transforms the glob pattern in a regexp: - // - escape "." with "\." - // - replace "*" by "[^.]*" - // - escape "$" with "\$" - // - add end-of-line match $ - globPattern = globPattern.replaceAll("\\$", "\\\\\\$"); - globPattern = globPattern.replaceAll("\\.", "\\\\."); - // prevent ** from being altered by the next rule, then process the * rule and finally - // the real ** rule (which is now @) - globPattern = globPattern.replaceAll("\\*\\*", "@"); - globPattern = globPattern.replaceAll("\\*", "[^.]*"); - globPattern = globPattern.replaceAll("@", ".*"); - globPattern += "$"; - - Pattern regexp = Pattern.compile(globPattern); - - for (Entry<String, ClassReader> entry : zipClasses.entrySet()) { - String class_name = entry.getKey(); - if (regexp.matcher(class_name).matches()) { - findClass(class_name, zipClasses, inOutFound); - } - } - } - - /** - * Checks all the classes defined in the JarClassName instance and uses BCEL to - * determine if they are derived from the given FQCN super class name. - * Inserts the super class and all the class objects found in the map. - */ - void findClassesDerivingFrom(String super_name, Map<String, ClassReader> zipClasses, - Map<String, ClassReader> inOutFound) throws LogAbortException { - ClassReader super_clazz = findClass(super_name, zipClasses, inOutFound); - - for (Entry<String, ClassReader> entry : zipClasses.entrySet()) { - String className = entry.getKey(); - if (super_name.equals(className)) { - continue; - } - ClassReader classReader = entry.getValue(); - ClassReader parent_cr = classReader; - while (parent_cr != null) { - String parent_name = internalToBinaryClassName(parent_cr.getSuperName()); - if (parent_name == null) { - // not found - break; - } else if (super_name.equals(parent_name)) { - inOutFound.put(className, classReader); - break; - } - parent_cr = zipClasses.get(parent_name); - } - } - } - - /** - * Instantiates a new DependencyVisitor. Useful for unit tests. - */ - DependencyVisitor getVisitor(Map<String, ClassReader> zipClasses, - Map<String, ClassReader> inKeep, - Map<String, ClassReader> outKeep, - Map<String, ClassReader> inDeps, - Map<String, ClassReader> outDeps) { - return new DependencyVisitor(zipClasses, inKeep, outKeep, inDeps, outDeps); - } - - /** - * Finds all dependencies for all classes in keepClasses which are also - * listed in zipClasses. Returns a map of all the dependencies found. - */ - Map<String, ClassReader> findDeps(Map<String, ClassReader> zipClasses, - Map<String, ClassReader> inOutKeepClasses) { - - TreeMap<String, ClassReader> deps = new TreeMap<String, ClassReader>(); - TreeMap<String, ClassReader> new_deps = new TreeMap<String, ClassReader>(); - TreeMap<String, ClassReader> new_keep = new TreeMap<String, ClassReader>(); - TreeMap<String, ClassReader> temp = new TreeMap<String, ClassReader>(); - - DependencyVisitor visitor = getVisitor(zipClasses, - inOutKeepClasses, new_keep, - deps, new_deps); - - for (ClassReader cr : inOutKeepClasses.values()) { - cr.accept(visitor, 0 /* flags */); - } - - while (new_deps.size() > 0 || new_keep.size() > 0) { - deps.putAll(new_deps); - inOutKeepClasses.putAll(new_keep); - - temp.clear(); - temp.putAll(new_deps); - temp.putAll(new_keep); - new_deps.clear(); - new_keep.clear(); - mLog.debug("Found %1$d to keep, %2$d dependencies.", - inOutKeepClasses.size(), deps.size()); - - for (ClassReader cr : temp.values()) { - cr.accept(visitor, 0 /* flags */); - } - } - - mLog.info("Found %1$d classes to keep, %2$d class dependencies.", - inOutKeepClasses.size(), deps.size()); - - return deps; - } - - - - // ---------------------------------- - - /** - * Visitor to collect all the type dependencies from a class. - */ - public class DependencyVisitor extends ClassVisitor { - - /** All classes found in the source JAR. */ - private final Map<String, ClassReader> mZipClasses; - /** Classes from which dependencies are to be found. */ - private final Map<String, ClassReader> mInKeep; - /** Dependencies already known. */ - private final Map<String, ClassReader> mInDeps; - /** New dependencies found by this visitor. */ - private final Map<String, ClassReader> mOutDeps; - /** New classes to keep as-is found by this visitor. */ - private final Map<String, ClassReader> mOutKeep; - - /** - * Creates a new visitor that will find all the dependencies for the visited class. - * Types which are already in the zipClasses, keepClasses or inDeps are not marked. - * New dependencies are marked in outDeps. - * - * @param zipClasses All classes found in the source JAR. - * @param inKeep Classes from which dependencies are to be found. - * @param inDeps Dependencies already known. - * @param outDeps New dependencies found by this visitor. - */ - public DependencyVisitor(Map<String, ClassReader> zipClasses, - Map<String, ClassReader> inKeep, - Map<String, ClassReader> outKeep, - Map<String,ClassReader> inDeps, - Map<String,ClassReader> outDeps) { - super(Opcodes.ASM4); - mZipClasses = zipClasses; - mInKeep = inKeep; - mOutKeep = outKeep; - mInDeps = inDeps; - mOutDeps = outDeps; - } - - /** - * Considers the given class name as a dependency. - * If it does, add to the mOutDeps map. - */ - public void considerName(String className) { - if (className == null) { - return; - } - - className = internalToBinaryClassName(className); - - // exclude classes that have already been found - if (mInKeep.containsKey(className) || - mOutKeep.containsKey(className) || - mInDeps.containsKey(className) || - mOutDeps.containsKey(className)) { - return; - } - - // exclude classes that are not part of the JAR file being examined - ClassReader cr = mZipClasses.get(className); - if (cr == null) { - return; - } - - try { - // exclude classes that are part of the default JRE (the one executing this program) - if (getClass().getClassLoader().loadClass(className) != null) { - return; - } - } catch (ClassNotFoundException e) { - // ignore - } - - // accept this class: - // - android classes are added to dependencies - // - non-android classes are added to the list of classes to keep as-is (they don't need - // to be stubbed). - if (className.indexOf("android") >= 0) { // TODO make configurable - mOutDeps.put(className, cr); - } else { - mOutKeep.put(className, cr); - } - } - - /** - * Considers this array of names using considerName(). - */ - public void considerNames(String[] classNames) { - if (classNames != null) { - for (String className : classNames) { - considerName(className); - } - } - } - - /** - * Considers this signature or type signature by invoking the {@link SignatureVisitor} - * on it. - */ - public void considerSignature(String signature) { - if (signature != null) { - SignatureReader sr = new SignatureReader(signature); - // SignatureReader.accept will call accessType so we don't really have - // to differentiate where the signature comes from. - sr.accept(new MySignatureVisitor()); - } - } - - /** - * Considers this {@link Type}. For arrays, the element type is considered. - * If the type is an object, it's internal name is considered. - */ - public void considerType(Type t) { - if (t != null) { - if (t.getSort() == Type.ARRAY) { - t = t.getElementType(); - } - if (t.getSort() == Type.OBJECT) { - considerName(t.getInternalName()); - } - } - } - - /** - * Considers a descriptor string. The descriptor is converted to a {@link Type} - * and then considerType() is invoked. - */ - public void considerDesc(String desc) { - if (desc != null) { - try { - Type t = Type.getType(desc); - considerType(t); - } catch (ArrayIndexOutOfBoundsException e) { - // ignore, not a valid type. - } - } - } - - - // --------------------------------------------------- - // --- ClassVisitor, FieldVisitor - // --------------------------------------------------- - - // Visits a class header - @Override - public void visit(int version, int access, String name, - String signature, String superName, String[] interfaces) { - // signature is the signature of this class. May be null if the class is not a generic - // one, and does not extend or implement generic classes or interfaces. - - if (signature != null) { - considerSignature(signature); - } - - // superName is the internal of name of the super class (see getInternalName). - // For interfaces, the super class is Object. May be null but only for the Object class. - considerName(superName); - - // interfaces is the internal names of the class's interfaces (see getInternalName). - // May be null. - considerNames(interfaces); - } - - - @Override - public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - // desc is the class descriptor of the annotation class. - considerDesc(desc); - return new MyAnnotationVisitor(); - } - - @Override - public void visitAttribute(Attribute attr) { - // pass - } - - // Visits the end of a class - @Override - public void visitEnd() { - // pass - } - - private class MyFieldVisitor extends FieldVisitor { - - public MyFieldVisitor() { - super(Opcodes.ASM4); - } - - @Override - public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - // desc is the class descriptor of the annotation class. - considerDesc(desc); - return new MyAnnotationVisitor(); - } - - @Override - public void visitAttribute(Attribute attr) { - // pass - } - - // Visits the end of a class - @Override - public void visitEnd() { - // pass - } - } - - @Override - public FieldVisitor visitField(int access, String name, String desc, - String signature, Object value) { - // desc is the field's descriptor (see Type). - considerDesc(desc); - - // signature is the field's signature. May be null if the field's type does not use - // generic types. - considerSignature(signature); - - return new MyFieldVisitor(); - } - - @Override - public void visitInnerClass(String name, String outerName, String innerName, int access) { - // name is the internal name of an inner class (see getInternalName). - considerName(name); - } - - @Override - public MethodVisitor visitMethod(int access, String name, String desc, - String signature, String[] exceptions) { - // desc is the method's descriptor (see Type). - considerDesc(desc); - // signature is the method's signature. May be null if the method parameters, return - // type and exceptions do not use generic types. - considerSignature(signature); - - return new MyMethodVisitor(); - } - - @Override - public void visitOuterClass(String owner, String name, String desc) { - // pass - } - - @Override - public void visitSource(String source, String debug) { - // pass - } - - - // --------------------------------------------------- - // --- MethodVisitor - // --------------------------------------------------- - - private class MyMethodVisitor extends MethodVisitor { - - public MyMethodVisitor() { - super(Opcodes.ASM4); - } - - - @Override - public AnnotationVisitor visitAnnotationDefault() { - return new MyAnnotationVisitor(); - } - - @Override - public void visitCode() { - // pass - } - - // field instruction - @Override - public void visitFieldInsn(int opcode, String owner, String name, String desc) { - // name is the field's name. - considerName(name); - // desc is the field's descriptor (see Type). - considerDesc(desc); - } - - @Override - public void visitFrame(int type, int local, Object[] local2, int stack, Object[] stack2) { - // pass - } - - @Override - public void visitIincInsn(int var, int increment) { - // pass -- an IINC instruction - } - - @Override - public void visitInsn(int opcode) { - // pass -- a zero operand instruction - } - - @Override - public void visitIntInsn(int opcode, int operand) { - // pass -- a single int operand instruction - } - - @Override - public void visitJumpInsn(int opcode, Label label) { - // pass -- a jump instruction - } - - @Override - public void visitLabel(Label label) { - // pass -- a label target - } - - // instruction to load a constant from the stack - @Override - public void visitLdcInsn(Object cst) { - if (cst instanceof Type) { - considerType((Type) cst); - } - } - - @Override - public void visitLineNumber(int line, Label start) { - // pass - } - - @Override - public void visitLocalVariable(String name, String desc, - String signature, Label start, Label end, int index) { - // desc is the type descriptor of this local variable. - considerDesc(desc); - // signature is the type signature of this local variable. May be null if the local - // variable type does not use generic types. - considerSignature(signature); - } - - @Override - public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) { - // pass -- a lookup switch instruction - } - - @Override - public void visitMaxs(int maxStack, int maxLocals) { - // pass - } - - // instruction that invokes a method - @Override - public void visitMethodInsn(int opcode, String owner, String name, String desc) { - - // owner is the internal name of the method's owner class - considerName(owner); - // desc is the method's descriptor (see Type). - considerDesc(desc); - } - - // instruction multianewarray, whatever that is - @Override - public void visitMultiANewArrayInsn(String desc, int dims) { - - // desc an array type descriptor. - considerDesc(desc); - } - - @Override - public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, - boolean visible) { - // desc is the class descriptor of the annotation class. - considerDesc(desc); - return new MyAnnotationVisitor(); - } - - @Override - public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels) { - // pass -- table switch instruction - - } - - @Override - public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { - // type is the internal name of the type of exceptions handled by the handler, - // or null to catch any exceptions (for "finally" blocks). - considerName(type); - } - - // type instruction - @Override - public void visitTypeInsn(int opcode, String type) { - // type is the operand of the instruction to be visited. This operand must be the - // internal name of an object or array class. - considerName(type); - } - - @Override - public void visitVarInsn(int opcode, int var) { - // pass -- local variable instruction - } - } - - private class MySignatureVisitor extends SignatureVisitor { - - public MySignatureVisitor() { - super(Opcodes.ASM4); - } - - // --------------------------------------------------- - // --- SignatureVisitor - // --------------------------------------------------- - - private String mCurrentSignatureClass = null; - - // Starts the visit of a signature corresponding to a class or interface type - @Override - public void visitClassType(String name) { - mCurrentSignatureClass = name; - considerName(name); - } - - // Visits an inner class - @Override - public void visitInnerClassType(String name) { - if (mCurrentSignatureClass != null) { - mCurrentSignatureClass += "$" + name; - considerName(mCurrentSignatureClass); - } - } - - @Override - public SignatureVisitor visitArrayType() { - return new MySignatureVisitor(); - } - - @Override - public void visitBaseType(char descriptor) { - // pass -- a primitive type, ignored - } - - @Override - public SignatureVisitor visitClassBound() { - return new MySignatureVisitor(); - } - - @Override - public SignatureVisitor visitExceptionType() { - return new MySignatureVisitor(); - } - - @Override - public void visitFormalTypeParameter(String name) { - // pass - } - - @Override - public SignatureVisitor visitInterface() { - return new MySignatureVisitor(); - } - - @Override - public SignatureVisitor visitInterfaceBound() { - return new MySignatureVisitor(); - } - - @Override - public SignatureVisitor visitParameterType() { - return new MySignatureVisitor(); - } - - @Override - public SignatureVisitor visitReturnType() { - return new MySignatureVisitor(); - } - - @Override - public SignatureVisitor visitSuperclass() { - return new MySignatureVisitor(); - } - - @Override - public SignatureVisitor visitTypeArgument(char wildcard) { - return new MySignatureVisitor(); - } - - @Override - public void visitTypeVariable(String name) { - // pass - } - - @Override - public void visitTypeArgument() { - // pass - } - } - - - // --------------------------------------------------- - // --- AnnotationVisitor - // --------------------------------------------------- - - private class MyAnnotationVisitor extends AnnotationVisitor { - - public MyAnnotationVisitor() { - super(Opcodes.ASM4); - } - - // Visits a primitive value of an annotation - @Override - public void visit(String name, Object value) { - // value is the actual value, whose type must be Byte, Boolean, Character, Short, - // Integer, Long, Float, Double, String or Type - if (value instanceof Type) { - considerType((Type) value); - } - } - - @Override - public AnnotationVisitor visitAnnotation(String name, String desc) { - // desc is the class descriptor of the nested annotation class. - considerDesc(desc); - return new MyAnnotationVisitor(); - } - - @Override - public AnnotationVisitor visitArray(String name) { - return new MyAnnotationVisitor(); - } - - @Override - public void visitEnum(String name, String desc, String value) { - // desc is the class descriptor of the enumeration class. - considerDesc(desc); - } - } - } -} diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java deleted file mode 100644 index a9ede26..0000000 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Copyright (C) 2008 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.layoutlib.create; - -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.ClassWriter; - -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.TreeMap; -import java.util.jar.JarEntry; -import java.util.jar.JarOutputStream; - -/** - * Class that generates a new JAR from a list of classes, some of which are to be kept as-is - * and some of which are to be stubbed partially or totally. - */ -public class AsmGenerator { - - /** Output logger. */ - private final Log mLog; - /** The path of the destination JAR to create. */ - private final String mOsDestJar; - /** List of classes to inject in the final JAR from _this_ archive. */ - private final Class<?>[] mInjectClasses; - /** The set of methods to stub out. */ - private final Set<String> mStubMethods; - /** All classes to output as-is, except if they have native methods. */ - private Map<String, ClassReader> mKeep; - /** All dependencies that must be completely stubbed. */ - private Map<String, ClassReader> mDeps; - /** Counter of number of classes renamed during transform. */ - private int mRenameCount; - /** FQCN Names of the classes to rename: map old-FQCN => new-FQCN */ - private final HashMap<String, String> mRenameClasses; - /** FQCN Names of "old" classes that were NOT renamed. This starts with the full list of - * old-FQCN to rename and they get erased as they get renamed. At the end, classes still - * left here are not in the code base anymore and thus were not renamed. */ - private HashSet<String> mClassesNotRenamed; - /** A map { FQCN => set { list of return types to delete from the FQCN } }. */ - private HashMap<String, Set<String>> mDeleteReturns; - /** A map { FQCN => set { method names } } of methods to rewrite as delegates. - * The special name {@link DelegateClassAdapter#ALL_NATIVES} can be used as in internal set. */ - private final HashMap<String, Set<String>> mDelegateMethods; - - /** - * Creates a new generator that can generate the output JAR with the stubbed classes. - * - * @param log Output logger. - * @param osDestJar The path of the destination JAR to create. - * @param createInfo Creation parameters. Must not be null. - */ - public AsmGenerator(Log log, String osDestJar, ICreateInfo createInfo) { - mLog = log; - mOsDestJar = osDestJar; - mInjectClasses = createInfo.getInjectedClasses(); - mStubMethods = new HashSet<String>(Arrays.asList(createInfo.getOverriddenMethods())); - - // Create the map/set of methods to change to delegates - mDelegateMethods = new HashMap<String, Set<String>>(); - for (String signature : createInfo.getDelegateMethods()) { - int pos = signature.indexOf('#'); - if (pos <= 0 || pos >= signature.length() - 1) { - continue; - } - String className = binaryToInternalClassName(signature.substring(0, pos)); - String methodName = signature.substring(pos + 1); - Set<String> methods = mDelegateMethods.get(className); - if (methods == null) { - methods = new HashSet<String>(); - mDelegateMethods.put(className, methods); - } - methods.add(methodName); - } - for (String className : createInfo.getDelegateClassNatives()) { - className = binaryToInternalClassName(className); - Set<String> methods = mDelegateMethods.get(className); - if (methods == null) { - methods = new HashSet<String>(); - mDelegateMethods.put(className, methods); - } - methods.add(DelegateClassAdapter.ALL_NATIVES); - } - - // Create the map of classes to rename. - mRenameClasses = new HashMap<String, String>(); - mClassesNotRenamed = new HashSet<String>(); - String[] renameClasses = createInfo.getRenamedClasses(); - int n = renameClasses.length; - for (int i = 0; i < n; i += 2) { - assert i + 1 < n; - // The ASM class names uses "/" separators, whereas regular FQCN use "." - String oldFqcn = binaryToInternalClassName(renameClasses[i]); - String newFqcn = binaryToInternalClassName(renameClasses[i + 1]); - mRenameClasses.put(oldFqcn, newFqcn); - mClassesNotRenamed.add(oldFqcn); - } - - // create the map of renamed class -> return type of method to delete. - mDeleteReturns = new HashMap<String, Set<String>>(); - String[] deleteReturns = createInfo.getDeleteReturns(); - Set<String> returnTypes = null; - String renamedClass = null; - for (String className : deleteReturns) { - // if we reach the end of a section, add it to the main map - if (className == null) { - if (returnTypes != null) { - mDeleteReturns.put(renamedClass, returnTypes); - } - - renamedClass = null; - continue; - } - - // if the renamed class is null, this is the beginning of a section - if (renamedClass == null) { - renamedClass = binaryToInternalClassName(className); - continue; - } - - // just a standard return type, we add it to the list. - if (returnTypes == null) { - returnTypes = new HashSet<String>(); - } - returnTypes.add(binaryToInternalClassName(className)); - } - } - - /** - * Returns the list of classes that have not been renamed yet. - * <p/> - * The names are "internal class names" rather than FQCN, i.e. they use "/" instead "." - * as package separators. - */ - public Set<String> getClassesNotRenamed() { - return mClassesNotRenamed; - } - - /** - * Utility that returns the internal ASM class name from a fully qualified binary class - * name. E.g. it returns android/view/View from android.view.View. - */ - String binaryToInternalClassName(String className) { - if (className == null) { - return null; - } else { - return className.replace('.', '/'); - } - } - - /** Sets the map of classes to output as-is, except if they have native methods */ - public void setKeep(Map<String, ClassReader> keep) { - mKeep = keep; - } - - /** Sets the map of dependencies that must be completely stubbed */ - public void setDeps(Map<String, ClassReader> deps) { - mDeps = deps; - } - - /** Gets the map of classes to output as-is, except if they have native methods */ - public Map<String, ClassReader> getKeep() { - return mKeep; - } - - /** Gets the map of dependencies that must be completely stubbed */ - public Map<String, ClassReader> getDeps() { - return mDeps; - } - - /** Generates the final JAR */ - public void generate() throws FileNotFoundException, IOException { - TreeMap<String, byte[]> all = new TreeMap<String, byte[]>(); - - for (Class<?> clazz : mInjectClasses) { - String name = classToEntryPath(clazz); - InputStream is = ClassLoader.getSystemResourceAsStream(name); - ClassReader cr = new ClassReader(is); - byte[] b = transform(cr, true /* stubNativesOnly */); - name = classNameToEntryPath(transformName(cr.getClassName())); - all.put(name, b); - } - - for (Entry<String, ClassReader> entry : mDeps.entrySet()) { - ClassReader cr = entry.getValue(); - byte[] b = transform(cr, true /* stubNativesOnly */); - String name = classNameToEntryPath(transformName(cr.getClassName())); - all.put(name, b); - } - - for (Entry<String, ClassReader> entry : mKeep.entrySet()) { - ClassReader cr = entry.getValue(); - byte[] b = transform(cr, true /* stubNativesOnly */); - String name = classNameToEntryPath(transformName(cr.getClassName())); - all.put(name, b); - } - - mLog.info("# deps classes: %d", mDeps.size()); - mLog.info("# keep classes: %d", mKeep.size()); - mLog.info("# renamed : %d", mRenameCount); - - createJar(new FileOutputStream(mOsDestJar), all); - mLog.info("Created JAR file %s", mOsDestJar); - } - - /** - * Writes the JAR file. - * - * @param outStream The file output stream were to write the JAR. - * @param all The map of all classes to output. - * @throws IOException if an I/O error has occurred - */ - void createJar(FileOutputStream outStream, Map<String,byte[]> all) throws IOException { - JarOutputStream jar = new JarOutputStream(outStream); - for (Entry<String, byte[]> entry : all.entrySet()) { - String name = entry.getKey(); - JarEntry jar_entry = new JarEntry(name); - jar.putNextEntry(jar_entry); - jar.write(entry.getValue()); - jar.closeEntry(); - } - jar.flush(); - jar.close(); - } - - /** - * Utility method that converts a fully qualified java name into a JAR entry path - * e.g. for the input "android.view.View" it returns "android/view/View.class" - */ - String classNameToEntryPath(String className) { - return className.replaceAll("\\.", "/").concat(".class"); - } - - /** - * Utility method to get the JAR entry path from a Class name. - * e.g. it returns someting like "com/foo/OuterClass$InnerClass1$InnerClass2.class" - */ - private String classToEntryPath(Class<?> clazz) { - String name = ""; - Class<?> parent; - while ((parent = clazz.getEnclosingClass()) != null) { - name = "$" + clazz.getSimpleName() + name; - clazz = parent; - } - return classNameToEntryPath(clazz.getCanonicalName() + name); - } - - /** - * Transforms a class. - * <p/> - * There are 3 kind of transformations: - * - * 1- For "mock" dependencies classes, we want to remove all code from methods and replace - * by a stub. Native methods must be implemented with this stub too. Abstract methods are - * left intact. Modified classes must be overridable (non-private, non-final). - * Native methods must be made non-final, non-private. - * - * 2- For "keep" classes, we want to rewrite all native methods as indicated above. - * If a class has native methods, it must also be made non-private, non-final. - * - * Note that unfortunately static methods cannot be changed to non-static (since static and - * non-static are invoked differently.) - */ - byte[] transform(ClassReader cr, boolean stubNativesOnly) { - - boolean hasNativeMethods = hasNativeMethods(cr); - - // Get the class name, as an internal name (e.g. com/android/SomeClass$InnerClass) - String className = cr.getClassName(); - - String newName = transformName(className); - // transformName returns its input argument if there's no need to rename the class - if (newName != className) { - mRenameCount++; - // This class is being renamed, so remove it from the list of classes not renamed. - mClassesNotRenamed.remove(className); - } - - mLog.debug("Transform %s%s%s%s", className, - newName == className ? "" : " (renamed to " + newName + ")", - hasNativeMethods ? " -- has natives" : "", - stubNativesOnly ? " -- stub natives only" : ""); - - // Rewrite the new class from scratch, without reusing the constant pool from the - // original class reader. - ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS); - - ClassVisitor rv = cw; - if (newName != className) { - rv = new RenameClassAdapter(cw, className, newName); - } - - ClassVisitor cv = new TransformClassAdapter(mLog, mStubMethods, - mDeleteReturns.get(className), - newName, rv, - stubNativesOnly, stubNativesOnly || hasNativeMethods); - - Set<String> delegateMethods = mDelegateMethods.get(className); - if (delegateMethods != null && !delegateMethods.isEmpty()) { - // If delegateMethods only contains one entry ALL_NATIVES and the class is - // known to have no native methods, just skip this step. - if (hasNativeMethods || - !(delegateMethods.size() == 1 && - delegateMethods.contains(DelegateClassAdapter.ALL_NATIVES))) { - cv = new DelegateClassAdapter(mLog, cv, className, delegateMethods); - } - } - - cr.accept(cv, 0 /* flags */); - return cw.toByteArray(); - } - - /** - * Should this class be renamed, this returns the new name. Otherwise it returns the - * original name. - * - * @param className The internal ASM name of the class that may have to be renamed - * @return A new transformed name or the original input argument. - */ - String transformName(String className) { - String newName = mRenameClasses.get(className); - if (newName != null) { - return newName; - } - int pos = className.indexOf('$'); - if (pos > 0) { - // Is this an inner class of a renamed class? - String base = className.substring(0, pos); - newName = mRenameClasses.get(base); - if (newName != null) { - return newName + className.substring(pos); - } - } - - return className; - } - - /** - * Returns true if a class has any native methods. - */ - boolean hasNativeMethods(ClassReader cr) { - ClassHasNativeVisitor cv = new ClassHasNativeVisitor(); - cr.accept(cv, 0 /* flags */); - return cv.hasNativeMethods(); - } - -} diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ClassHasNativeVisitor.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ClassHasNativeVisitor.java deleted file mode 100644 index 2c955fd..0000000 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ClassHasNativeVisitor.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2008 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.layoutlib.create; - -import com.android.tools.layoutlib.annotations.VisibleForTesting; -import com.android.tools.layoutlib.annotations.VisibleForTesting.Visibility; - -import org.objectweb.asm.AnnotationVisitor; -import org.objectweb.asm.Attribute; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.FieldVisitor; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; - -/** - * Indicates if a class contains any native methods. - */ -public class ClassHasNativeVisitor extends ClassVisitor { - public ClassHasNativeVisitor() { - super(Opcodes.ASM4); - } - - private boolean mHasNativeMethods = false; - - public boolean hasNativeMethods() { - return mHasNativeMethods; - } - - @VisibleForTesting(visibility=Visibility.PRIVATE) - protected void setHasNativeMethods(boolean hasNativeMethods, String methodName) { - mHasNativeMethods = hasNativeMethods; - } - - @Override - public void visit(int version, int access, String name, String signature, - String superName, String[] interfaces) { - // pass - } - - @Override - public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - // pass - return null; - } - - @Override - public void visitAttribute(Attribute attr) { - // pass - } - - @Override - public void visitEnd() { - // pass - } - - @Override - public FieldVisitor visitField(int access, String name, String desc, - String signature, Object value) { - // pass - return null; - } - - @Override - public void visitInnerClass(String name, String outerName, - String innerName, int access) { - // pass - } - - @Override - public MethodVisitor visitMethod(int access, String name, String desc, - String signature, String[] exceptions) { - if ((access & Opcodes.ACC_NATIVE) != 0) { - setHasNativeMethods(true, name); - } - return null; - } - - @Override - public void visitOuterClass(String owner, String name, String desc) { - // pass - } - - @Override - public void visitSource(String source, String debug) { - // pass - } - -} diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java deleted file mode 100644 index d955040..0000000 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright (C) 2008 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.layoutlib.create; - -import com.android.tools.layoutlib.annotations.LayoutlibDelegate; - -/** - * Describes the work to be done by {@link AsmGenerator}. - */ -public final class CreateInfo implements ICreateInfo { - - /** - * Returns the list of class from layoutlib_create to inject in layoutlib. - * The list can be empty but must not be null. - */ - @Override - public Class<?>[] getInjectedClasses() { - return INJECTED_CLASSES; - } - - /** - * Returns the list of methods to rewrite as delegates. - * The list can be empty but must not be null. - */ - @Override - public String[] getDelegateMethods() { - return DELEGATE_METHODS; - } - - /** - * Returns the list of classes on which to delegate all native methods. - * The list can be empty but must not be null. - */ - @Override - public String[] getDelegateClassNatives() { - return DELEGATE_CLASS_NATIVES; - } - - /** - * Returns The list of methods to stub out. Each entry must be in the form - * "package.package.OuterClass$InnerClass#MethodName". - * The list can be empty but must not be null. - * <p/> - * This usage is deprecated. Please use method 'delegates' instead. - */ - @Override - public String[] getOverriddenMethods() { - return OVERRIDDEN_METHODS; - } - - /** - * Returns the list of classes to rename, must be an even list: the binary FQCN - * of class to replace followed by the new FQCN. - * The list can be empty but must not be null. - */ - @Override - public String[] getRenamedClasses() { - return RENAMED_CLASSES; - } - - /** - * Returns the list of classes for which the methods returning them should be deleted. - * The array contains a list of null terminated section starting with the name of the class - * to rename in which the methods are deleted, followed by a list of return types identifying - * the methods to delete. - * The list can be empty but must not be null. - */ - @Override - public String[] getDeleteReturns() { - return DELETE_RETURNS; - } - - //----- - - /** - * The list of class from layoutlib_create to inject in layoutlib. - */ - private final static Class<?>[] INJECTED_CLASSES = new Class<?>[] { - OverrideMethod.class, - MethodListener.class, - MethodAdapter.class, - ICreateInfo.class, - CreateInfo.class, - LayoutlibDelegate.class - }; - - /** - * The list of methods to rewrite as delegates. - */ - public final static String[] DELEGATE_METHODS = new String[] { - "android.app.Fragment#instantiate", //(Landroid/content/Context;Ljava/lang/String;Landroid/os/Bundle;)Landroid/app/Fragment;", - "android.content.res.Resources$Theme#obtainStyledAttributes", - "android.content.res.Resources$Theme#resolveAttribute", - "android.content.res.TypedArray#getValueAt", - "android.graphics.BitmapFactory#finishDecode", - "android.os.Handler#sendMessageAtTime", - "android.os.HandlerThread#run", - "android.os.Build#getString", - "android.text.format.DateFormat#is24HourFormat", - "android.view.Choreographer#getRefreshRate", - "android.view.Display#updateDisplayInfoLocked", - "android.view.LayoutInflater#rInflate", - "android.view.LayoutInflater#parseInclude", - "android.view.View#isInEditMode", - "android.view.ViewRootImpl#isInTouchMode", - "android.view.WindowManagerGlobal#getWindowManagerService", - "android.view.inputmethod.InputMethodManager#getInstance", - "com.android.internal.util.XmlUtils#convertValueToInt", - "com.android.internal.textservice.ITextServicesManager$Stub#asInterface", - }; - - /** - * The list of classes on which to delegate all native methods. - */ - public final static String[] DELEGATE_CLASS_NATIVES = new String[] { - "android.animation.PropertyValuesHolder", - "android.graphics.AvoidXfermode", - "android.graphics.Bitmap", - "android.graphics.BitmapFactory", - "android.graphics.BitmapShader", - "android.graphics.BlurMaskFilter", - "android.graphics.Canvas", - "android.graphics.ColorFilter", - "android.graphics.ColorMatrixColorFilter", - "android.graphics.ComposePathEffect", - "android.graphics.ComposeShader", - "android.graphics.CornerPathEffect", - "android.graphics.DashPathEffect", - "android.graphics.DiscretePathEffect", - "android.graphics.DrawFilter", - "android.graphics.EmbossMaskFilter", - "android.graphics.LayerRasterizer", - "android.graphics.LightingColorFilter", - "android.graphics.LinearGradient", - "android.graphics.MaskFilter", - "android.graphics.Matrix", - "android.graphics.NinePatch", - "android.graphics.Paint", - "android.graphics.PaintFlagsDrawFilter", - "android.graphics.Path", - "android.graphics.PathDashPathEffect", - "android.graphics.PathEffect", - "android.graphics.PixelXorXfermode", - "android.graphics.PorterDuffColorFilter", - "android.graphics.PorterDuffXfermode", - "android.graphics.RadialGradient", - "android.graphics.Rasterizer", - "android.graphics.Region", - "android.graphics.Shader", - "android.graphics.SumPathEffect", - "android.graphics.SweepGradient", - "android.graphics.Typeface", - "android.graphics.Xfermode", - "android.os.SystemClock", - "android.text.AndroidBidi", - "android.util.FloatMath", - "android.view.Display", - "libcore.icu.ICU", - }; - - /** - * The list of methods to stub out. Each entry must be in the form - * "package.package.OuterClass$InnerClass#MethodName". - * This usage is deprecated. Please use method 'delegates' instead. - */ - private final static String[] OVERRIDDEN_METHODS = new String[] { - }; - - /** - * The list of classes to rename, must be an even list: the binary FQCN - * of class to replace followed by the new FQCN. - */ - private final static String[] RENAMED_CLASSES = - new String[] { - "android.os.ServiceManager", "android.os._Original_ServiceManager", - "android.util.LruCache", "android.util._Original_LruCache", - "android.view.SurfaceView", "android.view._Original_SurfaceView", - "android.view.accessibility.AccessibilityManager", "android.view.accessibility._Original_AccessibilityManager", - "android.webkit.WebView", "android.webkit._Original_WebView", - "com.android.internal.policy.PolicyManager", "com.android.internal.policy._Original_PolicyManager", - }; - - /** - * List of classes for which the methods returning them should be deleted. - * The array contains a list of null terminated section starting with the name of the class - * to rename in which the methods are deleted, followed by a list of return types identifying - * the methods to delete. - */ - private final static String[] DELETE_RETURNS = - new String[] { - null }; // separator, for next class/methods list. -} - diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java deleted file mode 100644 index 927be97..0000000 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (C) 2010 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.layoutlib.create; - -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; - -import java.util.Set; - -/** - * A {@link DelegateClassAdapter} can transform some methods from a class into - * delegates that defer the call to an associated delegate class. - * <p/> - * This is used to override specific methods and or all native methods in classes. - */ -public class DelegateClassAdapter extends ClassVisitor { - - /** Suffix added to original methods. */ - private static final String ORIGINAL_SUFFIX = "_Original"; - private static String CONSTRUCTOR = "<init>"; - private static String CLASS_INIT = "<clinit>"; - - public final static String ALL_NATIVES = "<<all_natives>>"; - - private final String mClassName; - private final Set<String> mDelegateMethods; - private final Log mLog; - - /** - * Creates a new {@link DelegateClassAdapter} that can transform some methods - * from a class into delegates that defer the call to an associated delegate class. - * <p/> - * This is used to override specific methods and or all native methods in classes. - * - * @param log The logger object. Must not be null. - * @param cv the class visitor to which this adapter must delegate calls. - * @param className The internal class name of the class to visit, - * e.g. <code>com/android/SomeClass$InnerClass</code>. - * @param delegateMethods The set of method names to modify and/or the - * special constant {@link #ALL_NATIVES} to convert all native methods. - */ - public DelegateClassAdapter(Log log, - ClassVisitor cv, - String className, - Set<String> delegateMethods) { - super(Opcodes.ASM4, cv); - mLog = log; - mClassName = className; - mDelegateMethods = delegateMethods; - } - - //---------------------------------- - // Methods from the ClassAdapter - - @Override - public MethodVisitor visitMethod(int access, String name, String desc, - String signature, String[] exceptions) { - - boolean isStatic = (access & Opcodes.ACC_STATIC) != 0; - boolean isNative = (access & Opcodes.ACC_NATIVE) != 0; - - boolean useDelegate = (isNative && mDelegateMethods.contains(ALL_NATIVES)) || - mDelegateMethods.contains(name); - - if (!useDelegate) { - // Not creating a delegate for this method, pass it as-is from the reader - // to the writer. - return super.visitMethod(access, name, desc, signature, exceptions); - } - - if (useDelegate) { - if (CONSTRUCTOR.equals(name) || CLASS_INIT.equals(name)) { - // We don't currently support generating delegates for constructors. - throw new UnsupportedOperationException( - String.format( - "Delegate doesn't support overriding constructor %1$s:%2$s(%3$s)", //$NON-NLS-1$ - mClassName, name, desc)); - } - } - - if (isNative) { - // Remove native flag - access = access & ~Opcodes.ACC_NATIVE; - MethodVisitor mwDelegate = super.visitMethod(access, name, desc, signature, exceptions); - - DelegateMethodAdapter2 a = new DelegateMethodAdapter2( - mLog, null /*mwOriginal*/, mwDelegate, mClassName, name, desc, isStatic); - - // A native has no code to visit, so we need to generate it directly. - a.generateDelegateCode(); - - return mwDelegate; - } - - // Given a non-native SomeClass.MethodName(), we want to generate 2 methods: - // - A copy of the original method named SomeClass.MethodName_Original(). - // The content is the original method as-is from the reader. - // - A brand new implementation of SomeClass.MethodName() which calls to a - // non-existing method named SomeClass_Delegate.MethodName(). - // The implementation of this 'delegate' method is done in layoutlib_brigde. - - int accessDelegate = access; - // change access to public for the original one - if (Main.sOptions.generatePublicAccess) { - access &= ~(Opcodes.ACC_PROTECTED | Opcodes.ACC_PRIVATE); - access |= Opcodes.ACC_PUBLIC; - } - - MethodVisitor mwOriginal = super.visitMethod(access, name + ORIGINAL_SUFFIX, - desc, signature, exceptions); - MethodVisitor mwDelegate = super.visitMethod(accessDelegate, name, - desc, signature, exceptions); - - DelegateMethodAdapter2 a = new DelegateMethodAdapter2( - mLog, mwOriginal, mwDelegate, mClassName, name, desc, isStatic); - return a; - } -} diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter2.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter2.java deleted file mode 100644 index 0000b22..0000000 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter2.java +++ /dev/null @@ -1,461 +0,0 @@ -/* - * Copyright (C) 2010 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.layoutlib.create; - -import com.android.tools.layoutlib.annotations.LayoutlibDelegate; - -import org.objectweb.asm.AnnotationVisitor; -import org.objectweb.asm.Attribute; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; - -import java.util.ArrayList; - -/** - * This method adapter generates delegate methods. - * <p/> - * Given a method {@code SomeClass.MethodName()}, this generates 1 or 2 methods: - * <ul> - * <li> A copy of the original method named {@code SomeClass.MethodName_Original()}. - * The content is the original method as-is from the reader. - * This step is omitted if the method is native, since it has no Java implementation. - * <li> A brand new implementation of {@code SomeClass.MethodName()} which calls to a - * non-existing method named {@code SomeClass_Delegate.MethodName()}. - * The implementation of this 'delegate' method is done in layoutlib_brigde. - * </ul> - * A method visitor is generally constructed to generate a single method; however - * here we might want to generate one or two depending on the context. To achieve - * that, the visitor here generates the 'original' method and acts as a no-op if - * no such method exists (e.g. when the original is a native method). - * The delegate method is generated after the {@code visitEnd} of the original method - * or by having the class adapter <em>directly</em> call {@link #generateDelegateCode()} - * for native methods. - * <p/> - * When generating the 'delegate', the implementation generates a call to a class - * class named <code><className>_Delegate</code> with static methods matching - * the methods to be overridden here. The methods have the same return type. - * The argument type list is the same except the "this" reference is passed first - * for non-static methods. - * <p/> - * A new annotation is added to these 'delegate' methods so that we can easily find them - * for automated testing. - * <p/> - * This class isn't intended to be generic or reusable. - * It is called by {@link DelegateClassAdapter}, which takes care of properly initializing - * the two method writers for the original and the delegate class, as needed, with their - * expected names. - * <p/> - * The class adapter also takes care of calling {@link #generateDelegateCode()} directly for - * a native and use the visitor pattern for non-natives. - * Note that native methods have, by definition, no code so there's nothing a visitor - * can visit. - * <p/> - * Instances of this class are not re-usable. - * The class adapter creates a new instance for each method. - */ -class DelegateMethodAdapter2 extends MethodVisitor { - - /** Suffix added to delegate classes. */ - public static final String DELEGATE_SUFFIX = "_Delegate"; - - /** The parent method writer to copy of the original method. - * Null when dealing with a native original method. */ - private MethodVisitor mOrgWriter; - /** The parent method writer to generate the delegating method. Never null. */ - private MethodVisitor mDelWriter; - /** The original method descriptor (return type + argument types.) */ - private String mDesc; - /** True if the original method is static. */ - private final boolean mIsStatic; - /** The internal class name (e.g. <code>com/android/SomeClass$InnerClass</code>.) */ - private final String mClassName; - /** The method name. */ - private final String mMethodName; - /** Logger object. */ - private final Log mLog; - - /** Array used to capture the first line number information from the original method - * and duplicate it in the delegate. */ - private Object[] mDelegateLineNumber; - - /** - * Creates a new {@link DelegateMethodAdapter2} that will transform this method - * into a delegate call. - * <p/> - * See {@link DelegateMethodAdapter2} for more details. - * - * @param log The logger object. Must not be null. - * @param mvOriginal The parent method writer to copy of the original method. - * Must be {@code null} when dealing with a native original method. - * @param mvDelegate The parent method writer to generate the delegating method. - * Must never be null. - * @param className The internal class name of the class to visit, - * e.g. <code>com/android/SomeClass$InnerClass</code>. - * @param methodName The simple name of the method. - * @param desc A method descriptor (c.f. {@link Type#getReturnType(String)} + - * {@link Type#getArgumentTypes(String)}) - * @param isStatic True if the method is declared static. - */ - public DelegateMethodAdapter2(Log log, - MethodVisitor mvOriginal, - MethodVisitor mvDelegate, - String className, - String methodName, - String desc, - boolean isStatic) { - super(Opcodes.ASM4); - mLog = log; - mOrgWriter = mvOriginal; - mDelWriter = mvDelegate; - mClassName = className; - mMethodName = methodName; - mDesc = desc; - mIsStatic = isStatic; - } - - /** - * Generates the new code for the method. - * <p/> - * For native methods, this must be invoked directly by {@link DelegateClassAdapter} - * (since they have no code to visit). - * <p/> - * Otherwise for non-native methods the {@link DelegateClassAdapter} simply needs to - * return this instance of {@link DelegateMethodAdapter2} and let the normal visitor pattern - * invoke it as part of the {@link ClassReader#accept(ClassVisitor, int)} workflow and then - * this method will be invoked from {@link MethodVisitor#visitEnd()}. - */ - public void generateDelegateCode() { - /* - * The goal is to generate a call to a static delegate method. - * If this method is non-static, the first parameter will be 'this'. - * All the parameters must be passed and then the eventual return type returned. - * - * Example, let's say we have a method such as - * public void myMethod(int a, Object b, ArrayList<String> c) { ... } - * - * We'll want to create a body that calls a delegate method like this: - * TheClass_Delegate.myMethod(this, a, b, c); - * - * If the method is non-static and the class name is an inner class (e.g. has $ in its - * last segment), we want to push the 'this' of the outer class first: - * OuterClass_InnerClass_Delegate.myMethod( - * OuterClass.this, - * OuterClass$InnerClass.this, - * a, b, c); - * - * Only one level of inner class is supported right now, for simplicity and because - * we don't need more. - * - * The generated class name is the current class name with "_Delegate" appended to it. - * One thing to realize is that we don't care about generics -- since generic types - * are erased at build time, they have no influence on the method name being called. - */ - - // Add our annotation - AnnotationVisitor aw = mDelWriter.visitAnnotation( - Type.getObjectType(Type.getInternalName(LayoutlibDelegate.class)).toString(), - true); // visible at runtime - if (aw != null) { - aw.visitEnd(); - } - - mDelWriter.visitCode(); - - if (mDelegateLineNumber != null) { - Object[] p = mDelegateLineNumber; - mDelWriter.visitLineNumber((Integer) p[0], (Label) p[1]); - } - - ArrayList<Type> paramTypes = new ArrayList<Type>(); - String delegateClassName = mClassName + DELEGATE_SUFFIX; - boolean pushedArg0 = false; - int maxStack = 0; - - // Check if the last segment of the class name has inner an class. - // Right now we only support one level of inner classes. - Type outerType = null; - int slash = mClassName.lastIndexOf('/'); - int dol = mClassName.lastIndexOf('$'); - if (dol != -1 && dol > slash && dol == mClassName.indexOf('$')) { - String outerClass = mClassName.substring(0, dol); - outerType = Type.getObjectType(outerClass); - - // Change a delegate class name to "com/foo/Outer_Inner_Delegate" - delegateClassName = delegateClassName.replace('$', '_'); - } - - // For an instance method (e.g. non-static), push the 'this' preceded - // by the 'this' of any outer class, if any. - if (!mIsStatic) { - - if (outerType != null) { - // The first-level inner class has a package-protected member called 'this$0' - // that points to the outer class. - - // Push this.getField("this$0") on the call stack. - mDelWriter.visitVarInsn(Opcodes.ALOAD, 0); // var 0 = this - mDelWriter.visitFieldInsn(Opcodes.GETFIELD, - mClassName, // class where the field is defined - "this$0", // field name - outerType.getDescriptor()); // type of the field - maxStack++; - paramTypes.add(outerType); - - } - - // Push "this" for the instance method, which is always ALOAD 0 - mDelWriter.visitVarInsn(Opcodes.ALOAD, 0); - maxStack++; - pushedArg0 = true; - paramTypes.add(Type.getObjectType(mClassName)); - } - - // Push all other arguments. Start at arg 1 if we already pushed 'this' above. - Type[] argTypes = Type.getArgumentTypes(mDesc); - int maxLocals = pushedArg0 ? 1 : 0; - for (Type t : argTypes) { - int size = t.getSize(); - mDelWriter.visitVarInsn(t.getOpcode(Opcodes.ILOAD), maxLocals); - maxLocals += size; - maxStack += size; - paramTypes.add(t); - } - - // Construct the descriptor of the delegate based on the parameters - // we pushed on the call stack. The return type remains unchanged. - String desc = Type.getMethodDescriptor( - Type.getReturnType(mDesc), - paramTypes.toArray(new Type[paramTypes.size()])); - - // Invoke the static delegate - mDelWriter.visitMethodInsn(Opcodes.INVOKESTATIC, - delegateClassName, - mMethodName, - desc); - - Type returnType = Type.getReturnType(mDesc); - mDelWriter.visitInsn(returnType.getOpcode(Opcodes.IRETURN)); - - mDelWriter.visitMaxs(maxStack, maxLocals); - mDelWriter.visitEnd(); - - // For debugging now. Maybe we should collect these and store them in - // a text file for helping create the delegates. We could also compare - // the text file to a golden and break the build on unsupported changes - // or regressions. Even better we could fancy-print something that looks - // like the expected Java method declaration. - mLog.debug("Delegate: %1$s # %2$s %3$s", delegateClassName, mMethodName, desc); - } - - /* Pass down to visitor writer. In this implementation, either do nothing. */ - @Override - public void visitCode() { - if (mOrgWriter != null) { - mOrgWriter.visitCode(); - } - } - - /* - * visitMaxs is called just before visitEnd if there was any code to rewrite. - */ - @Override - public void visitMaxs(int maxStack, int maxLocals) { - if (mOrgWriter != null) { - mOrgWriter.visitMaxs(maxStack, maxLocals); - } - } - - /** End of visiting. Generate the delegating code. */ - @Override - public void visitEnd() { - if (mOrgWriter != null) { - mOrgWriter.visitEnd(); - } - generateDelegateCode(); - } - - /* Writes all annotation from the original method. */ - @Override - public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - if (mOrgWriter != null) { - return mOrgWriter.visitAnnotation(desc, visible); - } else { - return null; - } - } - - /* Writes all annotation default values from the original method. */ - @Override - public AnnotationVisitor visitAnnotationDefault() { - if (mOrgWriter != null) { - return mOrgWriter.visitAnnotationDefault(); - } else { - return null; - } - } - - @Override - public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, - boolean visible) { - if (mOrgWriter != null) { - return mOrgWriter.visitParameterAnnotation(parameter, desc, visible); - } else { - return null; - } - } - - /* Writes all attributes from the original method. */ - @Override - public void visitAttribute(Attribute attr) { - if (mOrgWriter != null) { - mOrgWriter.visitAttribute(attr); - } - } - - /* - * Only writes the first line number present in the original code so that source - * viewers can direct to the correct method, even if the content doesn't match. - */ - @Override - public void visitLineNumber(int line, Label start) { - // Capture the first line values for the new delegate method - if (mDelegateLineNumber == null) { - mDelegateLineNumber = new Object[] { line, start }; - } - if (mOrgWriter != null) { - mOrgWriter.visitLineNumber(line, start); - } - } - - @Override - public void visitInsn(int opcode) { - if (mOrgWriter != null) { - mOrgWriter.visitInsn(opcode); - } - } - - @Override - public void visitLabel(Label label) { - if (mOrgWriter != null) { - mOrgWriter.visitLabel(label); - } - } - - @Override - public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { - if (mOrgWriter != null) { - mOrgWriter.visitTryCatchBlock(start, end, handler, type); - } - } - - @Override - public void visitMethodInsn(int opcode, String owner, String name, String desc) { - if (mOrgWriter != null) { - mOrgWriter.visitMethodInsn(opcode, owner, name, desc); - } - } - - @Override - public void visitFieldInsn(int opcode, String owner, String name, String desc) { - if (mOrgWriter != null) { - mOrgWriter.visitFieldInsn(opcode, owner, name, desc); - } - } - - @Override - public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) { - if (mOrgWriter != null) { - mOrgWriter.visitFrame(type, nLocal, local, nStack, stack); - } - } - - @Override - public void visitIincInsn(int var, int increment) { - if (mOrgWriter != null) { - mOrgWriter.visitIincInsn(var, increment); - } - } - - @Override - public void visitIntInsn(int opcode, int operand) { - if (mOrgWriter != null) { - mOrgWriter.visitIntInsn(opcode, operand); - } - } - - @Override - public void visitJumpInsn(int opcode, Label label) { - if (mOrgWriter != null) { - mOrgWriter.visitJumpInsn(opcode, label); - } - } - - @Override - public void visitLdcInsn(Object cst) { - if (mOrgWriter != null) { - mOrgWriter.visitLdcInsn(cst); - } - } - - @Override - public void visitLocalVariable(String name, String desc, String signature, - Label start, Label end, int index) { - if (mOrgWriter != null) { - mOrgWriter.visitLocalVariable(name, desc, signature, start, end, index); - } - } - - @Override - public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) { - if (mOrgWriter != null) { - mOrgWriter.visitLookupSwitchInsn(dflt, keys, labels); - } - } - - @Override - public void visitMultiANewArrayInsn(String desc, int dims) { - if (mOrgWriter != null) { - mOrgWriter.visitMultiANewArrayInsn(desc, dims); - } - } - - @Override - public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels) { - if (mOrgWriter != null) { - mOrgWriter.visitTableSwitchInsn(min, max, dflt, labels); - } - } - - @Override - public void visitTypeInsn(int opcode, String type) { - if (mOrgWriter != null) { - mOrgWriter.visitTypeInsn(opcode, type); - } - } - - @Override - public void visitVarInsn(int opcode, int var) { - if (mOrgWriter != null) { - mOrgWriter.visitVarInsn(opcode, var); - } - } - -} diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DependencyFinder.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DependencyFinder.java deleted file mode 100644 index c988c70..0000000 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DependencyFinder.java +++ /dev/null @@ -1,787 +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.tools.layoutlib.create; - -import com.android.tools.layoutlib.annotations.VisibleForTesting; -import com.android.tools.layoutlib.annotations.VisibleForTesting.Visibility; - -import org.objectweb.asm.AnnotationVisitor; -import org.objectweb.asm.Attribute; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.FieldVisitor; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; -import org.objectweb.asm.signature.SignatureReader; -import org.objectweb.asm.signature.SignatureVisitor; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.Enumeration; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; -import java.util.TreeMap; -import java.util.TreeSet; -import java.util.zip.ZipEntry; -import java.util.zip.ZipFile; - -/** - * Analyzes the input JAR using the ASM java bytecode manipulation library - * to list the classes and their dependencies. A "dependency" is a class - * used by another class. - */ -public class DependencyFinder { - - // Note: a bunch of stuff has package-level access for unit tests. Consider it private. - - /** Output logger. */ - private final Log mLog; - - /** - * Creates a new analyzer. - * - * @param log The log output. - */ - public DependencyFinder(Log log) { - mLog = log; - } - - /** - * Starts the analysis using parameters from the constructor. - * - * @param osJarPath The input source JARs to parse. - * @return A pair: [0]: map { class FQCN => set of FQCN class dependencies }. - * [1]: map { missing class FQCN => set of FQCN class that uses it. } - */ - public List<Map<String, Set<String>>> findDeps(List<String> osJarPath) throws IOException { - - Map<String, ClassReader> zipClasses = parseZip(osJarPath); - mLog.info("Found %d classes in input JAR%s.", - zipClasses.size(), - osJarPath.size() > 1 ? "s" : ""); - - Map<String, Set<String>> deps = findClassesDeps(zipClasses); - - Map<String, Set<String>> missing = findMissingClasses(deps, zipClasses.keySet()); - - List<Map<String, Set<String>>> result = new ArrayList<Map<String,Set<String>>>(2); - result.add(deps); - result.add(missing); - return result; - } - - /** - * Prints dependencies to the current logger, found stuff and missing stuff. - */ - public void printAllDeps(List<Map<String, Set<String>>> result) { - assert result.size() == 2; - Map<String, Set<String>> deps = result.get(0); - Map<String, Set<String>> missing = result.get(1); - - // Print all dependences found in the format: - // +Found: <FQCN from zip> - // uses: FQCN - - mLog.info("++++++ %d Entries found in source JARs", deps.size()); - mLog.info(""); - - for (Entry<String, Set<String>> entry : deps.entrySet()) { - mLog.info( "+Found : %s", entry.getKey()); - for (String dep : entry.getValue()) { - mLog.info(" uses: %s", dep); - } - - mLog.info(""); - } - - - // Now print all missing dependences in the format: - // -Missing <FQCN>: - // used by: <FQCN> - - mLog.info(""); - mLog.info("------ %d Entries missing from source JARs", missing.size()); - mLog.info(""); - - for (Entry<String, Set<String>> entry : missing.entrySet()) { - mLog.info( "-Missing : %s", entry.getKey()); - for (String dep : entry.getValue()) { - mLog.info(" used by: %s", dep); - } - - mLog.info(""); - } - } - - /** - * Prints only a summary of the missing dependencies to the current logger. - */ - public void printMissingDeps(List<Map<String, Set<String>>> result) { - assert result.size() == 2; - @SuppressWarnings("unused") Map<String, Set<String>> deps = result.get(0); - Map<String, Set<String>> missing = result.get(1); - - for (String fqcn : missing.keySet()) { - mLog.info("%s", fqcn); - } - } - - // ---------------- - - /** - * Parses a JAR file and returns a list of all classes founds using a map - * class name => ASM ClassReader. Class names are in the form "android.view.View". - */ - Map<String,ClassReader> parseZip(List<String> jarPathList) throws IOException { - TreeMap<String, ClassReader> classes = new TreeMap<String, ClassReader>(); - - for (String jarPath : jarPathList) { - ZipFile zip = new ZipFile(jarPath); - Enumeration<? extends ZipEntry> entries = zip.entries(); - ZipEntry entry; - while (entries.hasMoreElements()) { - entry = entries.nextElement(); - if (entry.getName().endsWith(".class")) { - ClassReader cr = new ClassReader(zip.getInputStream(entry)); - String className = classReaderToClassName(cr); - classes.put(className, cr); - } - } - } - - return classes; - } - - /** - * Utility that returns the fully qualified binary class name for a ClassReader. - * E.g. it returns something like android.view.View. - */ - static String classReaderToClassName(ClassReader classReader) { - if (classReader == null) { - return null; - } else { - return classReader.getClassName().replace('/', '.'); - } - } - - /** - * Utility that returns the fully qualified binary class name from a path-like FQCN. - * E.g. it returns android.view.View from android/view/View. - */ - static String internalToBinaryClassName(String className) { - if (className == null) { - return null; - } else { - return className.replace('/', '.'); - } - } - - /** - * Finds all dependencies for all classes in keepClasses which are also - * listed in zipClasses. Returns a map of all the dependencies found. - */ - Map<String, Set<String>> findClassesDeps(Map<String, ClassReader> zipClasses) { - - // The dependencies that we'll collect. - // It's a map Class name => uses class names. - Map<String, Set<String>> dependencyMap = new TreeMap<String, Set<String>>(); - - DependencyVisitor visitor = getVisitor(); - - int count = 0; - try { - for (Entry<String, ClassReader> entry : zipClasses.entrySet()) { - String name = entry.getKey(); - - TreeSet<String> set = new TreeSet<String>(); - dependencyMap.put(name, set); - visitor.setDependencySet(set); - - ClassReader cr = entry.getValue(); - cr.accept(visitor, 0 /* flags */); - - visitor.setDependencySet(null); - - mLog.debugNoln("Visited %d classes\r", ++count); - } - } finally { - mLog.debugNoln("\n"); - } - - return dependencyMap; - } - - /** - * Computes which classes FQCN were found as dependencies that are NOT listed - * in the original JAR classes. - * - * @param deps The map { FQCN => dependencies[] } returned by {@link #findClassesDeps(Map)}. - * @param zipClasses The set of all classes FQCN found in the JAR files. - * @return A map { FQCN not found in the zipClasses => classes using it } - */ - private Map<String, Set<String>> findMissingClasses( - Map<String, Set<String>> deps, - Set<String> zipClasses) { - Map<String, Set<String>> missing = new TreeMap<String, Set<String>>(); - - for (Entry<String, Set<String>> entry : deps.entrySet()) { - String name = entry.getKey(); - - for (String dep : entry.getValue()) { - if (!zipClasses.contains(dep)) { - // This dependency doesn't exist in the zip classes. - Set<String> set = missing.get(dep); - if (set == null) { - set = new TreeSet<String>(); - missing.put(dep, set); - } - set.add(name); - } - } - - } - - return missing; - } - - - // ---------------------------------- - - /** - * Instantiates a new DependencyVisitor. Useful for unit tests. - */ - @VisibleForTesting(visibility=Visibility.PRIVATE) - DependencyVisitor getVisitor() { - return new DependencyVisitor(); - } - - /** - * Visitor to collect all the type dependencies from a class. - */ - public class DependencyVisitor extends ClassVisitor { - - private Set<String> mCurrentDepSet; - - /** - * Creates a new visitor that will find all the dependencies for the visited class. - */ - public DependencyVisitor() { - super(Opcodes.ASM4); - } - - /** - * Sets the {@link Set} where to record direct dependencies for this class. - * This will change before each {@link ClassReader#accept(ClassVisitor, int)} call. - */ - public void setDependencySet(Set<String> set) { - mCurrentDepSet = set; - } - - /** - * Considers the given class name as a dependency. - */ - public void considerName(String className) { - if (className == null) { - return; - } - - className = internalToBinaryClassName(className); - - try { - // exclude classes that are part of the default JRE (the one executing this program) - if (getClass().getClassLoader().loadClass(className) != null) { - return; - } - } catch (ClassNotFoundException e) { - // ignore - } - - // Add it to the dependency set for the currently visited class, as needed. - assert mCurrentDepSet != null; - if (mCurrentDepSet != null) { - mCurrentDepSet.add(className); - } - } - - /** - * Considers this array of names using considerName(). - */ - public void considerNames(String[] classNames) { - if (classNames != null) { - for (String className : classNames) { - considerName(className); - } - } - } - - /** - * Considers this signature or type signature by invoking the {@link SignatureVisitor} - * on it. - */ - public void considerSignature(String signature) { - if (signature != null) { - SignatureReader sr = new SignatureReader(signature); - // SignatureReader.accept will call accessType so we don't really have - // to differentiate where the signature comes from. - sr.accept(new MySignatureVisitor()); - } - } - - /** - * Considers this {@link Type}. For arrays, the element type is considered. - * If the type is an object, it's internal name is considered. - */ - public void considerType(Type t) { - if (t != null) { - if (t.getSort() == Type.ARRAY) { - t = t.getElementType(); - } - if (t.getSort() == Type.OBJECT) { - considerName(t.getInternalName()); - } - } - } - - /** - * Considers a descriptor string. The descriptor is converted to a {@link Type} - * and then considerType() is invoked. - */ - public boolean considerDesc(String desc) { - if (desc != null) { - try { - if (desc.length() > 0 && desc.charAt(0) == '(') { - // This is a method descriptor with arguments and a return type. - Type t = Type.getReturnType(desc); - considerType(t); - - for (Type arg : Type.getArgumentTypes(desc)) { - considerType(arg); - } - - } else { - Type t = Type.getType(desc); - considerType(t); - } - return true; - } catch (ArrayIndexOutOfBoundsException e) { - // ignore, not a valid type. - } - } - return false; - } - - - // --------------------------------------------------- - // --- ClassVisitor, FieldVisitor - // --------------------------------------------------- - - // Visits a class header - @Override - public void visit(int version, int access, String name, - String signature, String superName, String[] interfaces) { - // signature is the signature of this class. May be null if the class is not a generic - // one, and does not extend or implement generic classes or interfaces. - - if (signature != null) { - considerSignature(signature); - } - - // superName is the internal of name of the super class (see getInternalName). - // For interfaces, the super class is Object. May be null but only for the Object class. - considerName(superName); - - // interfaces is the internal names of the class's interfaces (see getInternalName). - // May be null. - considerNames(interfaces); - } - - - @Override - public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - // desc is the class descriptor of the annotation class. - considerDesc(desc); - return new MyAnnotationVisitor(); - } - - @Override - public void visitAttribute(Attribute attr) { - // pass - } - - // Visits the end of a class - @Override - public void visitEnd() { - // pass - } - - private class MyFieldVisitor extends FieldVisitor { - - public MyFieldVisitor() { - super(Opcodes.ASM4); - } - - @Override - public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - // desc is the class descriptor of the annotation class. - considerDesc(desc); - return new MyAnnotationVisitor(); - } - - @Override - public void visitAttribute(Attribute attr) { - // pass - } - - // Visits the end of a class - @Override - public void visitEnd() { - // pass - } - } - - @Override - public FieldVisitor visitField(int access, String name, String desc, - String signature, Object value) { - // desc is the field's descriptor (see Type). - considerDesc(desc); - - // signature is the field's signature. May be null if the field's type does not use - // generic types. - considerSignature(signature); - - return new MyFieldVisitor(); - } - - @Override - public void visitInnerClass(String name, String outerName, String innerName, int access) { - // name is the internal name of an inner class (see getInternalName). - // Note: outerName/innerName seems to be null when we're reading the - // _Original_ClassName classes generated by layoutlib_create. - if (outerName != null) { - considerName(name); - } - } - - @Override - public MethodVisitor visitMethod(int access, String name, String desc, - String signature, String[] exceptions) { - // desc is the method's descriptor (see Type). - considerDesc(desc); - // signature is the method's signature. May be null if the method parameters, return - // type and exceptions do not use generic types. - considerSignature(signature); - - return new MyMethodVisitor(); - } - - @Override - public void visitOuterClass(String owner, String name, String desc) { - // pass - } - - @Override - public void visitSource(String source, String debug) { - // pass - } - - - // --------------------------------------------------- - // --- MethodVisitor - // --------------------------------------------------- - - private class MyMethodVisitor extends MethodVisitor { - - public MyMethodVisitor() { - super(Opcodes.ASM4); - } - - - @Override - public AnnotationVisitor visitAnnotationDefault() { - return new MyAnnotationVisitor(); - } - - @Override - public void visitCode() { - // pass - } - - // field instruction - @Override - public void visitFieldInsn(int opcode, String owner, String name, String desc) { - // name is the field's name. - // desc is the field's descriptor (see Type). - considerDesc(desc); - } - - @Override - public void visitFrame(int type, int local, Object[] local2, int stack, Object[] stack2) { - // pass - } - - @Override - public void visitIincInsn(int var, int increment) { - // pass -- an IINC instruction - } - - @Override - public void visitInsn(int opcode) { - // pass -- a zero operand instruction - } - - @Override - public void visitIntInsn(int opcode, int operand) { - // pass -- a single int operand instruction - } - - @Override - public void visitJumpInsn(int opcode, Label label) { - // pass -- a jump instruction - } - - @Override - public void visitLabel(Label label) { - // pass -- a label target - } - - // instruction to load a constant from the stack - @Override - public void visitLdcInsn(Object cst) { - if (cst instanceof Type) { - considerType((Type) cst); - } - } - - @Override - public void visitLineNumber(int line, Label start) { - // pass - } - - @Override - public void visitLocalVariable(String name, String desc, - String signature, Label start, Label end, int index) { - // desc is the type descriptor of this local variable. - considerDesc(desc); - // signature is the type signature of this local variable. May be null if the local - // variable type does not use generic types. - considerSignature(signature); - } - - @Override - public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) { - // pass -- a lookup switch instruction - } - - @Override - public void visitMaxs(int maxStack, int maxLocals) { - // pass - } - - // instruction that invokes a method - @Override - public void visitMethodInsn(int opcode, String owner, String name, String desc) { - - // owner is the internal name of the method's owner class - if (!considerDesc(owner) && owner.indexOf('/') != -1) { - considerName(owner); - } - // desc is the method's descriptor (see Type). - considerDesc(desc); - } - - // instruction multianewarray, whatever that is - @Override - public void visitMultiANewArrayInsn(String desc, int dims) { - - // desc an array type descriptor. - considerDesc(desc); - } - - @Override - public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, - boolean visible) { - // desc is the class descriptor of the annotation class. - considerDesc(desc); - return new MyAnnotationVisitor(); - } - - @Override - public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels) { - // pass -- table switch instruction - - } - - @Override - public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { - // type is the internal name of the type of exceptions handled by the handler, - // or null to catch any exceptions (for "finally" blocks). - considerName(type); - } - - // type instruction - @Override - public void visitTypeInsn(int opcode, String type) { - // type is the operand of the instruction to be visited. This operand must be the - // internal name of an object or array class. - considerName(type); - } - - @Override - public void visitVarInsn(int opcode, int var) { - // pass -- local variable instruction - } - } - - private class MySignatureVisitor extends SignatureVisitor { - - public MySignatureVisitor() { - super(Opcodes.ASM4); - } - - // --------------------------------------------------- - // --- SignatureVisitor - // --------------------------------------------------- - - private String mCurrentSignatureClass = null; - - // Starts the visit of a signature corresponding to a class or interface type - @Override - public void visitClassType(String name) { - mCurrentSignatureClass = name; - considerName(name); - } - - // Visits an inner class - @Override - public void visitInnerClassType(String name) { - if (mCurrentSignatureClass != null) { - mCurrentSignatureClass += "$" + name; - considerName(mCurrentSignatureClass); - } - } - - @Override - public SignatureVisitor visitArrayType() { - return new MySignatureVisitor(); - } - - @Override - public void visitBaseType(char descriptor) { - // pass -- a primitive type, ignored - } - - @Override - public SignatureVisitor visitClassBound() { - return new MySignatureVisitor(); - } - - @Override - public SignatureVisitor visitExceptionType() { - return new MySignatureVisitor(); - } - - @Override - public void visitFormalTypeParameter(String name) { - // pass - } - - @Override - public SignatureVisitor visitInterface() { - return new MySignatureVisitor(); - } - - @Override - public SignatureVisitor visitInterfaceBound() { - return new MySignatureVisitor(); - } - - @Override - public SignatureVisitor visitParameterType() { - return new MySignatureVisitor(); - } - - @Override - public SignatureVisitor visitReturnType() { - return new MySignatureVisitor(); - } - - @Override - public SignatureVisitor visitSuperclass() { - return new MySignatureVisitor(); - } - - @Override - public SignatureVisitor visitTypeArgument(char wildcard) { - return new MySignatureVisitor(); - } - - @Override - public void visitTypeVariable(String name) { - // pass - } - - @Override - public void visitTypeArgument() { - // pass - } - } - - - // --------------------------------------------------- - // --- AnnotationVisitor - // --------------------------------------------------- - - private class MyAnnotationVisitor extends AnnotationVisitor { - - public MyAnnotationVisitor() { - super(Opcodes.ASM4); - } - - // Visits a primitive value of an annotation - @Override - public void visit(String name, Object value) { - // value is the actual value, whose type must be Byte, Boolean, Character, Short, - // Integer, Long, Float, Double, String or Type - if (value instanceof Type) { - considerType((Type) value); - } - } - - @Override - public AnnotationVisitor visitAnnotation(String name, String desc) { - // desc is the class descriptor of the nested annotation class. - considerDesc(desc); - return new MyAnnotationVisitor(); - } - - @Override - public AnnotationVisitor visitArray(String name) { - return new MyAnnotationVisitor(); - } - - @Override - public void visitEnum(String name, String desc, String value) { - // desc is the class descriptor of the enumeration class. - considerDesc(desc); - } - } - } -} diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java deleted file mode 100644 index 40c1706..0000000 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (C) 2010 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.layoutlib.create; - -/** - * Interface describing the work to be done by {@link AsmGenerator}. - */ -public interface ICreateInfo { - - /** - * Returns the list of class from layoutlib_create to inject in layoutlib. - * The list can be empty but must not be null. - */ - public abstract Class<?>[] getInjectedClasses(); - - /** - * Returns the list of methods to rewrite as delegates. - * The list can be empty but must not be null. - */ - public abstract String[] getDelegateMethods(); - - /** - * Returns the list of classes on which to delegate all native methods. - * The list can be empty but must not be null. - */ - public abstract String[] getDelegateClassNatives(); - - /** - * Returns The list of methods to stub out. Each entry must be in the form - * "package.package.OuterClass$InnerClass#MethodName". - * The list can be empty but must not be null. - */ - public abstract String[] getOverriddenMethods(); - - /** - * Returns the list of classes to rename, must be an even list: the binary FQCN - * of class to replace followed by the new FQCN. - * The list can be empty but must not be null. - */ - public abstract String[] getRenamedClasses(); - - /** - * Returns the list of classes for which the methods returning them should be deleted. - * The array contains a list of null terminated section starting with the name of the class - * to rename in which the methods are deleted, followed by a list of return types identifying - * the methods to delete. - * The list can be empty but must not be null. - */ - public abstract String[] getDeleteReturns(); - -} diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Log.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Log.java deleted file mode 100644 index c3ba591..0000000 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Log.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (C) 2008 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.layoutlib.create; - -import java.io.PrintWriter; -import java.io.StringWriter; - -public class Log { - - private boolean mVerbose = false; - - public void setVerbose(boolean verbose) { - mVerbose = verbose; - } - - public void debug(String format, Object... args) { - if (mVerbose) { - info(format, args); - } - } - - /** Similar to debug() but doesn't do a \n automatically. */ - public void debugNoln(String format, Object... args) { - if (mVerbose) { - String s = String.format(format, args); - System.out.print(s); - } - } - - public void info(String format, Object... args) { - String s = String.format(format, args); - outPrintln(s); - } - - public void error(String format, Object... args) { - String s = String.format(format, args); - errPrintln(s); - } - - public void exception(Throwable t, String format, Object... args) { - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - t.printStackTrace(pw); - pw.flush(); - error(format + "\n" + sw.toString(), args); - } - - /** for unit testing */ - protected void errPrintln(String msg) { - System.err.println(msg); - } - - /** for unit testing */ - protected void outPrintln(String msg) { - System.out.println(msg); - } - -} diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/LogAbortException.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/LogAbortException.java deleted file mode 100644 index dc4b4a7..0000000 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/LogAbortException.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright (C) 2008 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.layoutlib.create; - -public class LogAbortException extends Exception { - - private final String mFormat; - private final Object[] mArgs; - - public LogAbortException(String format, Object... args) { - mFormat = format; - mArgs = args; - } - - public void error(Log log) { - log.error(mFormat, mArgs); - } -} diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java deleted file mode 100644 index 9cd74db..0000000 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (C) 2008 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.layoutlib.create; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; - - -/** - * Entry point for the layoutlib_create tool. - * <p/> - * The tool does not currently rely on any external configuration file. - * Instead the configuration is mostly done via the {@link CreateInfo} class. - * <p/> - * For a complete description of the tool and its implementation, please refer to - * the "README.txt" file at the root of this project. - * <p/> - * For a quick test, invoke this as follows: - * <pre> - * $ make layoutlib - * </pre> - * which does: - * <pre> - * $ make layoutlib_create <bunch of framework jars> - * $ java -jar out/host/linux-x86/framework/layoutlib_create.jar \ - * out/host/common/obj/JAVA_LIBRARIES/temp_layoutlib_intermediates/javalib.jar \ - * out/target/common/obj/JAVA_LIBRARIES/core_intermediates/classes.jar \ - * out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar - * </pre> - */ -public class Main { - - public static class Options { - public boolean generatePublicAccess = true; - public boolean listAllDeps = false; - public boolean listOnlyMissingDeps = false; - } - - public static final Options sOptions = new Options(); - - public static void main(String[] args) { - - Log log = new Log(); - - ArrayList<String> osJarPath = new ArrayList<String>(); - String[] osDestJar = { null }; - - if (!processArgs(log, args, osJarPath, osDestJar)) { - log.error("Usage: layoutlib_create [-v] [-p] output.jar input.jar ..."); - log.error("Usage: layoutlib_create [-v] [--list-deps|--missing-deps] input.jar ..."); - System.exit(1); - } - - if (sOptions.listAllDeps || sOptions.listOnlyMissingDeps) { - System.exit(listDeps(osJarPath, log)); - - } else { - System.exit(createLayoutLib(osDestJar[0], osJarPath, log)); - } - - - System.exit(1); - } - - private static int createLayoutLib(String osDestJar, ArrayList<String> osJarPath, Log log) { - log.info("Output: %1$s", osDestJar); - for (String path : osJarPath) { - log.info("Input : %1$s", path); - } - - try { - AsmGenerator agen = new AsmGenerator(log, osDestJar, new CreateInfo()); - - AsmAnalyzer aa = new AsmAnalyzer(log, osJarPath, agen, - new String[] { // derived from - "android.view.View", - "android.app.Fragment" - }, - new String[] { // include classes - "android.*", // for android.R - "android.util.*", - "com.android.internal.util.*", - "android.view.*", - "android.widget.*", - "com.android.internal.widget.*", - "android.text.**", - "android.graphics.*", - "android.graphics.drawable.*", - "android.content.*", - "android.content.res.*", - "org.apache.harmony.xml.*", - "com.android.internal.R**", - "android.pim.*", // for datepicker - "android.os.*", // for android.os.Handler - "android.database.ContentObserver", // for Digital clock - }); - aa.analyze(); - agen.generate(); - - // Throw an error if any class failed to get renamed by the generator - // - // IMPORTANT: if you're building the platform and you get this error message, - // it means the renameClasses[] array in AsmGenerator needs to be updated: some - // class should have been renamed but it was not found in the input JAR files. - Set<String> notRenamed = agen.getClassesNotRenamed(); - if (notRenamed.size() > 0) { - // (80-column guide below for error formatting) - // 01234567890123456789012345678901234567890123456789012345678901234567890123456789 - log.error( - "ERROR when running layoutlib_create: the following classes are referenced\n" + - "by tools/layoutlib/create but were not actually found in the input JAR files.\n" + - "This may be due to some platform classes having been renamed."); - for (String fqcn : notRenamed) { - log.error("- Class not found: %s", fqcn.replace('/', '.')); - } - for (String path : osJarPath) { - log.info("- Input JAR : %1$s", path); - } - return 1; - } - - return 0; - } catch (IOException e) { - log.exception(e, "Failed to load jar"); - } catch (LogAbortException e) { - e.error(log); - } - - return 1; - } - - private static int listDeps(ArrayList<String> osJarPath, Log log) { - DependencyFinder df = new DependencyFinder(log); - try { - List<Map<String, Set<String>>> result = df.findDeps(osJarPath); - if (sOptions.listAllDeps) { - df.printAllDeps(result); - } else if (sOptions.listOnlyMissingDeps) { - df.printMissingDeps(result); - } - } catch (IOException e) { - log.exception(e, "Failed to load jar"); - } - - return 0; - } - - /** - * Returns true if args where properly parsed. - * Returns false if program should exit with command-line usage. - * <p/> - * Note: the String[0] is an output parameter wrapped in an array, since there is no - * "out" parameter support. - */ - private static boolean processArgs(Log log, String[] args, - ArrayList<String> osJarPath, String[] osDestJar) { - boolean needs_dest = true; - for (int i = 0; i < args.length; i++) { - String s = args[i]; - if (s.equals("-v")) { - log.setVerbose(true); - } else if (s.equals("-p")) { - sOptions.generatePublicAccess = false; - } else if (s.equals("--list-deps")) { - sOptions.listAllDeps = true; - needs_dest = false; - } else if (s.equals("--missing-deps")) { - sOptions.listOnlyMissingDeps = true; - needs_dest = false; - } else if (!s.startsWith("-")) { - if (needs_dest && osDestJar[0] == null) { - osDestJar[0] = s; - } else { - osJarPath.add(s); - } - } else { - log.error("Unknow argument: %s", s); - return false; - } - } - - if (osJarPath.isEmpty()) { - log.error("Missing parameter: path to input jar"); - return false; - } - if (needs_dest && osDestJar[0] == null) { - log.error("Missing parameter: path to output jar"); - return false; - } - - sOptions.generatePublicAccess = false; - - return true; - } -} diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/MethodAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/MethodAdapter.java deleted file mode 100644 index 7d1e4cf..0000000 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/MethodAdapter.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright (C) 2008 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.layoutlib.create; - - -/** - * An adapter to make it easier to use {@link MethodListener}. - * <p/> - * The adapter calls the void {@link #onInvokeV(String, boolean, Object)} listener - * for all types (I, L, F, D and A), returning 0 or null as appropriate. - */ -public class MethodAdapter implements MethodListener { - /** - * A stub method is being invoked. - * <p/> - * Known limitation: caller arguments are not available. - * - * @param signature The signature of the method being invoked, composed of the - * binary class name followed by the method descriptor (aka argument - * types). Example: "com/foo/MyClass/InnerClass/printInt(I)V". - * @param isNative True if the method was a native method. - * @param caller The calling object. Null for static methods, "this" for instance methods. - */ - @Override - public void onInvokeV(String signature, boolean isNative, Object caller) { - } - - /** - * Same as {@link #onInvokeV(String, boolean, Object)} but returns an integer or similar. - * @see #onInvokeV(String, boolean, Object) - * @return an integer, or a boolean, or a short or a byte. - */ - @Override - public int onInvokeI(String signature, boolean isNative, Object caller) { - onInvokeV(signature, isNative, caller); - return 0; - } - - /** - * Same as {@link #onInvokeV(String, boolean, Object)} but returns a long. - * @see #onInvokeV(String, boolean, Object) - * @return a long. - */ - @Override - public long onInvokeL(String signature, boolean isNative, Object caller) { - onInvokeV(signature, isNative, caller); - return 0; - } - - /** - * Same as {@link #onInvokeV(String, boolean, Object)} but returns a float. - * @see #onInvokeV(String, boolean, Object) - * @return a float. - */ - @Override - public float onInvokeF(String signature, boolean isNative, Object caller) { - onInvokeV(signature, isNative, caller); - return 0; - } - - /** - * Same as {@link #onInvokeV(String, boolean, Object)} but returns a double. - * @see #onInvokeV(String, boolean, Object) - * @return a double. - */ - @Override - public double onInvokeD(String signature, boolean isNative, Object caller) { - onInvokeV(signature, isNative, caller); - return 0; - } - - /** - * Same as {@link #onInvokeV(String, boolean, Object)} but returns an object. - * @see #onInvokeV(String, boolean, Object) - * @return an object. - */ - @Override - public Object onInvokeA(String signature, boolean isNative, Object caller) { - onInvokeV(signature, isNative, caller); - return null; - } -} - diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/MethodListener.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/MethodListener.java deleted file mode 100644 index 6fc2b24..0000000 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/MethodListener.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2008 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.layoutlib.create; - - -/** - * Interface to allow a method invocation to be listened upon. - * <p/> - * This is used by {@link OverrideMethod} to register a listener for methods that - * have been stubbed by the {@link AsmGenerator}. At runtime the stub will call either a - * default global listener or a specific listener based on the method signature. - */ -public interface MethodListener { - /** - * A stub method is being invoked. - * <p/> - * Known limitation: caller arguments are not available. - * - * @param signature The signature of the method being invoked, composed of the - * binary class name followed by the method descriptor (aka argument - * types). Example: "com/foo/MyClass/InnerClass/printInt(I)V". - * @param isNative True if the method was a native method. - * @param caller The calling object. Null for static methods, "this" for instance methods. - */ - public void onInvokeV(String signature, boolean isNative, Object caller); - - /** - * Same as {@link #onInvokeV(String, boolean, Object)} but returns an integer or similar. - * @see #onInvokeV(String, boolean, Object) - * @return an integer, or a boolean, or a short or a byte. - */ - public int onInvokeI(String signature, boolean isNative, Object caller); - - /** - * Same as {@link #onInvokeV(String, boolean, Object)} but returns a long. - * @see #onInvokeV(String, boolean, Object) - * @return a long. - */ - public long onInvokeL(String signature, boolean isNative, Object caller); - - /** - * Same as {@link #onInvokeV(String, boolean, Object)} but returns a float. - * @see #onInvokeV(String, boolean, Object) - * @return a float. - */ - public float onInvokeF(String signature, boolean isNative, Object caller); - - /** - * Same as {@link #onInvokeV(String, boolean, Object)} but returns a double. - * @see #onInvokeV(String, boolean, Object) - * @return a double. - */ - public double onInvokeD(String signature, boolean isNative, Object caller); - - /** - * Same as {@link #onInvokeV(String, boolean, Object)} but returns an object. - * @see #onInvokeV(String, boolean, Object) - * @return an object. - */ - public Object onInvokeA(String signature, boolean isNative, Object caller); -} - diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/OverrideMethod.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/OverrideMethod.java deleted file mode 100644 index a6aff99..0000000 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/OverrideMethod.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2008 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.layoutlib.create; - -import java.util.HashMap; - -/** - * Allows stub methods from LayoutLib to be overriden at runtime. - * <p/> - * Implementation note: all types required by this class(inner/outer classes & interfaces) - * must be referenced by the injectClass argument to {@link AsmGenerator} in Main.java; - * Otherwise they won't be accessible in layoutlib.jar at runtime. - */ -public final class OverrideMethod { - - /** Map of method overridden. */ - private static HashMap<String, MethodListener> sMethods = new HashMap<String, MethodListener>(); - /** Default listener for all method not listed in sMethods. Nothing if null. */ - private static MethodListener sDefaultListener = null; - - /** - * Sets the default listener for all methods not specifically handled. - * Null means to do nothing. - */ - public static void setDefaultListener(MethodListener listener) { - sDefaultListener = listener; - } - - /** - * Defines or reset a listener for the given method signature. - * - * @param signature The signature of the method being invoked, composed of the - * binary class name followed by the method descriptor (aka argument - * types). Example: "com/foo/MyClass/InnerClass/printInt(I)V" - * @param listener The new listener. Removes it if null. - */ - public static void setMethodListener(String signature, MethodListener listener) { - if (listener == null) { - sMethods.remove(signature); - } else { - sMethods.put(signature, listener); - } - } - - /** - * Invokes the specific listener for the given signature or the default one if defined. - * <p/> - * This version invokes the method listener for the void return type. - * <p/> - * Note: this is not intended to be used by the LayoutLib Bridge. It is intended to be called - * by the stubbed methods generated by the LayoutLib_create tool. - * - * @param signature The signature of the method being invoked, composed of the - * binary class name followed by the method descriptor (aka argument - * types). Example: "com/foo/MyClass/InnerClass/printInt(I)V". - * @param isNative True if the method was a native method. - * @param caller The calling object. Null for static methods, "this" for instance methods. - */ - public static void invokeV(String signature, boolean isNative, Object caller) { - MethodListener i = sMethods.get(signature); - if (i != null) { - i.onInvokeV(signature, isNative, caller); - } else if (sDefaultListener != null) { - sDefaultListener.onInvokeV(signature, isNative, caller); - } - } - - /** - * Invokes the specific listener for the int return type. - * @see #invokeV(String, boolean, Object) - */ - public static int invokeI(String signature, boolean isNative, Object caller) { - MethodListener i = sMethods.get(signature); - if (i != null) { - return i.onInvokeI(signature, isNative, caller); - } else if (sDefaultListener != null) { - return sDefaultListener.onInvokeI(signature, isNative, caller); - } - return 0; - } - - /** - * Invokes the specific listener for the long return type. - * @see #invokeV(String, boolean, Object) - */ - public static long invokeL(String signature, boolean isNative, Object caller) { - MethodListener i = sMethods.get(signature); - if (i != null) { - return i.onInvokeL(signature, isNative, caller); - } else if (sDefaultListener != null) { - return sDefaultListener.onInvokeL(signature, isNative, caller); - } - return 0; - } - - /** - * Invokes the specific listener for the float return type. - * @see #invokeV(String, boolean, Object) - */ - public static float invokeF(String signature, boolean isNative, Object caller) { - MethodListener i = sMethods.get(signature); - if (i != null) { - return i.onInvokeF(signature, isNative, caller); - } else if (sDefaultListener != null) { - return sDefaultListener.onInvokeF(signature, isNative, caller); - } - return 0; - } - - /** - * Invokes the specific listener for the double return type. - * @see #invokeV(String, boolean, Object) - */ - public static double invokeD(String signature, boolean isNative, Object caller) { - MethodListener i = sMethods.get(signature); - if (i != null) { - return i.onInvokeD(signature, isNative, caller); - } else if (sDefaultListener != null) { - return sDefaultListener.onInvokeD(signature, isNative, caller); - } - return 0; - } - - /** - * Invokes the specific listener for the object return type. - * @see #invokeV(String, boolean, Object) - */ - public static Object invokeA(String signature, boolean isNative, Object caller) { - MethodListener i = sMethods.get(signature); - if (i != null) { - return i.onInvokeA(signature, isNative, caller); - } else if (sDefaultListener != null) { - return sDefaultListener.onInvokeA(signature, isNative, caller); - } - return null; - } -} diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/RenameClassAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/RenameClassAdapter.java deleted file mode 100644 index 383cbb8..0000000 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/RenameClassAdapter.java +++ /dev/null @@ -1,463 +0,0 @@ -/* - * Copyright (C) 2008 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.layoutlib.create; - -import org.objectweb.asm.AnnotationVisitor; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.ClassWriter; -import org.objectweb.asm.FieldVisitor; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; -import org.objectweb.asm.signature.SignatureReader; -import org.objectweb.asm.signature.SignatureVisitor; -import org.objectweb.asm.signature.SignatureWriter; - -/** - * This class visitor renames a class from a given old name to a given new name. - * The class visitor will also rename all inner classes and references in the methods. - * <p/> - * - * For inner classes, this handles only the case where the outer class name changes. - * The inner class name should remain the same. - */ -public class RenameClassAdapter extends ClassVisitor { - - - private final String mOldName; - private final String mNewName; - private String mOldBase; - private String mNewBase; - - /** - * Creates a class visitor that renames a class from a given old name to a given new name. - * The class visitor will also rename all inner classes and references in the methods. - * The names must be full qualified internal ASM names (e.g. com/blah/MyClass$InnerClass). - */ - public RenameClassAdapter(ClassWriter cv, String oldName, String newName) { - super(Opcodes.ASM4, cv); - mOldBase = mOldName = oldName; - mNewBase = mNewName = newName; - - int pos = mOldName.indexOf('$'); - if (pos > 0) { - mOldBase = mOldName.substring(0, pos); - } - pos = mNewName.indexOf('$'); - if (pos > 0) { - mNewBase = mNewName.substring(0, pos); - } - - assert (mOldBase == null && mNewBase == null) || (mOldBase != null && mNewBase != null); - } - - - /** - * Renames a type descriptor, e.g. "Lcom.package.MyClass;" - * If the type doesn't need to be renamed, returns the input string as-is. - */ - String renameTypeDesc(String desc) { - if (desc == null) { - return null; - } - - return renameType(Type.getType(desc)); - } - - /** - * Renames an object type, e.g. "Lcom.package.MyClass;" or an array type that has an - * object element, e.g. "[Lcom.package.MyClass;" - * If the type doesn't need to be renamed, returns the internal name of the input type. - */ - String renameType(Type type) { - if (type == null) { - return null; - } - - if (type.getSort() == Type.OBJECT) { - String in = type.getInternalName(); - return "L" + renameInternalType(in) + ";"; - } else if (type.getSort() == Type.ARRAY) { - StringBuilder sb = new StringBuilder(); - for (int n = type.getDimensions(); n > 0; n--) { - sb.append('['); - } - sb.append(renameType(type.getElementType())); - return sb.toString(); - } - return type.getDescriptor(); - } - - /** - * Renames an object type, e.g. "Lcom.package.MyClass;" or an array type that has an - * object element, e.g. "[Lcom.package.MyClass;". - * This is like renameType() except that it returns a Type object. - * If the type doesn't need to be renamed, returns the input type object. - */ - Type renameTypeAsType(Type type) { - if (type == null) { - return null; - } - - if (type.getSort() == Type.OBJECT) { - String in = type.getInternalName(); - String newIn = renameInternalType(in); - if (newIn != in) { - return Type.getType("L" + newIn + ";"); - } - } else if (type.getSort() == Type.ARRAY) { - StringBuilder sb = new StringBuilder(); - for (int n = type.getDimensions(); n > 0; n--) { - sb.append('['); - } - sb.append(renameType(type.getElementType())); - return Type.getType(sb.toString()); - } - return type; - } - - /** - * Renames an internal type name, e.g. "com.package.MyClass". - * If the type doesn't need to be renamed, returns the input string as-is. - * <p/> - * The internal type of some of the MethodVisitor turns out to be a type - descriptor sometimes so descriptors are renamed too. - */ - String renameInternalType(String type) { - if (type == null) { - return null; - } - - if (type.equals(mOldName)) { - return mNewName; - } - - if (mOldBase != mOldName && type.equals(mOldBase)) { - return mNewBase; - } - - int pos = type.indexOf('$'); - if (pos == mOldBase.length() && type.startsWith(mOldBase)) { - return mNewBase + type.substring(pos); - } - - // The internal type of some of the MethodVisitor turns out to be a type - // descriptor sometimes. This is the case with visitTypeInsn(type) and - // visitMethodInsn(owner). We try to detect it and adjust it here. - if (type.indexOf(';') > 0) { - type = renameTypeDesc(type); - } - - return type; - } - - /** - * Renames a method descriptor, i.e. applies renameType to all arguments and to the - * return value. - */ - String renameMethodDesc(String desc) { - if (desc == null) { - return null; - } - - Type[] args = Type.getArgumentTypes(desc); - - StringBuilder sb = new StringBuilder("("); - for (Type arg : args) { - String name = renameType(arg); - sb.append(name); - } - sb.append(')'); - - Type ret = Type.getReturnType(desc); - String name = renameType(ret); - sb.append(name); - - return sb.toString(); - } - - - /** - * Renames the ClassSignature handled by ClassVisitor.visit - * or the MethodTypeSignature handled by ClassVisitor.visitMethod. - */ - String renameTypeSignature(String sig) { - if (sig == null) { - return null; - } - SignatureReader reader = new SignatureReader(sig); - SignatureWriter writer = new SignatureWriter(); - reader.accept(new RenameSignatureAdapter(writer)); - sig = writer.toString(); - return sig; - } - - - /** - * Renames the FieldTypeSignature handled by ClassVisitor.visitField - * or MethodVisitor.visitLocalVariable. - */ - String renameFieldSignature(String sig) { - if (sig == null) { - return null; - } - SignatureReader reader = new SignatureReader(sig); - SignatureWriter writer = new SignatureWriter(); - reader.acceptType(new RenameSignatureAdapter(writer)); - sig = writer.toString(); - return sig; - } - - - //---------------------------------- - // Methods from the ClassAdapter - - @Override - public void visit(int version, int access, String name, String signature, - String superName, String[] interfaces) { - name = renameInternalType(name); - superName = renameInternalType(superName); - signature = renameTypeSignature(signature); - - super.visit(version, access, name, signature, superName, interfaces); - } - - @Override - public void visitInnerClass(String name, String outerName, String innerName, int access) { - assert outerName.equals(mOldName); - outerName = renameInternalType(outerName); - name = outerName + "$" + innerName; - super.visitInnerClass(name, outerName, innerName, access); - } - - @Override - public MethodVisitor visitMethod(int access, String name, String desc, - String signature, String[] exceptions) { - desc = renameMethodDesc(desc); - signature = renameTypeSignature(signature); - MethodVisitor mw = super.visitMethod(access, name, desc, signature, exceptions); - return new RenameMethodAdapter(mw); - } - - @Override - public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - desc = renameTypeDesc(desc); - return super.visitAnnotation(desc, visible); - } - - @Override - public FieldVisitor visitField(int access, String name, String desc, - String signature, Object value) { - desc = renameTypeDesc(desc); - signature = renameFieldSignature(signature); - return super.visitField(access, name, desc, signature, value); - } - - - //---------------------------------- - - /** - * A method visitor that renames all references from an old class name to a new class name. - */ - public class RenameMethodAdapter extends MethodVisitor { - - /** - * Creates a method visitor that renames all references from a given old name to a given new - * name. The method visitor will also rename all inner classes. - * The names must be full qualified internal ASM names (e.g. com/blah/MyClass$InnerClass). - */ - public RenameMethodAdapter(MethodVisitor mv) { - super(Opcodes.ASM4, mv); - } - - @Override - public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - desc = renameTypeDesc(desc); - - return super.visitAnnotation(desc, visible); - } - - @Override - public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, boolean visible) { - desc = renameTypeDesc(desc); - - return super.visitParameterAnnotation(parameter, desc, visible); - } - - @Override - public void visitTypeInsn(int opcode, String type) { - type = renameInternalType(type); - - super.visitTypeInsn(opcode, type); - } - - @Override - public void visitFieldInsn(int opcode, String owner, String name, String desc) { - owner = renameInternalType(owner); - desc = renameTypeDesc(desc); - - super.visitFieldInsn(opcode, owner, name, desc); - } - - @Override - public void visitMethodInsn(int opcode, String owner, String name, String desc) { - owner = renameInternalType(owner); - desc = renameMethodDesc(desc); - - super.visitMethodInsn(opcode, owner, name, desc); - } - - @Override - public void visitLdcInsn(Object cst) { - // If cst is a Type, this means the code is trying to pull the .class constant - // for this class, so it needs to be renamed too. - if (cst instanceof Type) { - cst = renameTypeAsType((Type) cst); - } - super.visitLdcInsn(cst); - } - - @Override - public void visitMultiANewArrayInsn(String desc, int dims) { - desc = renameTypeDesc(desc); - - super.visitMultiANewArrayInsn(desc, dims); - } - - @Override - public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { - type = renameInternalType(type); - - super.visitTryCatchBlock(start, end, handler, type); - } - - @Override - public void visitLocalVariable(String name, String desc, String signature, - Label start, Label end, int index) { - desc = renameTypeDesc(desc); - signature = renameFieldSignature(signature); - - super.visitLocalVariable(name, desc, signature, start, end, index); - } - - } - - //---------------------------------- - - public class RenameSignatureAdapter extends SignatureVisitor { - - private final SignatureVisitor mSv; - - public RenameSignatureAdapter(SignatureVisitor sv) { - super(Opcodes.ASM4); - mSv = sv; - } - - @Override - public void visitClassType(String name) { - name = renameInternalType(name); - mSv.visitClassType(name); - } - - @Override - public void visitInnerClassType(String name) { - name = renameInternalType(name); - mSv.visitInnerClassType(name); - } - - @Override - public SignatureVisitor visitArrayType() { - SignatureVisitor sv = mSv.visitArrayType(); - return new RenameSignatureAdapter(sv); - } - - @Override - public void visitBaseType(char descriptor) { - mSv.visitBaseType(descriptor); - } - - @Override - public SignatureVisitor visitClassBound() { - SignatureVisitor sv = mSv.visitClassBound(); - return new RenameSignatureAdapter(sv); - } - - @Override - public void visitEnd() { - mSv.visitEnd(); - } - - @Override - public SignatureVisitor visitExceptionType() { - SignatureVisitor sv = mSv.visitExceptionType(); - return new RenameSignatureAdapter(sv); - } - - @Override - public void visitFormalTypeParameter(String name) { - mSv.visitFormalTypeParameter(name); - } - - @Override - public SignatureVisitor visitInterface() { - SignatureVisitor sv = mSv.visitInterface(); - return new RenameSignatureAdapter(sv); - } - - @Override - public SignatureVisitor visitInterfaceBound() { - SignatureVisitor sv = mSv.visitInterfaceBound(); - return new RenameSignatureAdapter(sv); - } - - @Override - public SignatureVisitor visitParameterType() { - SignatureVisitor sv = mSv.visitParameterType(); - return new RenameSignatureAdapter(sv); - } - - @Override - public SignatureVisitor visitReturnType() { - SignatureVisitor sv = mSv.visitReturnType(); - return new RenameSignatureAdapter(sv); - } - - @Override - public SignatureVisitor visitSuperclass() { - SignatureVisitor sv = mSv.visitSuperclass(); - return new RenameSignatureAdapter(sv); - } - - @Override - public void visitTypeArgument() { - mSv.visitTypeArgument(); - } - - @Override - public SignatureVisitor visitTypeArgument(char wildcard) { - SignatureVisitor sv = mSv.visitTypeArgument(wildcard); - return new RenameSignatureAdapter(sv); - } - - @Override - public void visitTypeVariable(String name) { - mSv.visitTypeVariable(name); - } - - } -} diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/StubMethodAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/StubMethodAdapter.java deleted file mode 100644 index 51e7535..0000000 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/StubMethodAdapter.java +++ /dev/null @@ -1,376 +0,0 @@ -/* - * Copyright (C) 2008 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.layoutlib.create; - -import org.objectweb.asm.AnnotationVisitor; -import org.objectweb.asm.Attribute; -import org.objectweb.asm.Label; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; - -/** - * This method adapter rewrites a method by discarding the original code and generating - * a stub depending on the return type. Original annotations are passed along unchanged. - */ -class StubMethodAdapter extends MethodVisitor { - - private static String CONSTRUCTOR = "<init>"; - private static String CLASS_INIT = "<clinit>"; - - /** The parent method writer */ - private MethodVisitor mParentVisitor; - /** The method return type. Can be null. */ - private Type mReturnType; - /** Message to be printed by stub methods. */ - private String mInvokeSignature; - /** Flag to output the first line number. */ - private boolean mOutputFirstLineNumber = true; - /** Flag that is true when implementing a constructor, to accept all original - * code calling the original super constructor. */ - private boolean mIsInitMethod = false; - - private boolean mMessageGenerated; - private final boolean mIsStatic; - private final boolean mIsNative; - - public StubMethodAdapter(MethodVisitor mv, String methodName, Type returnType, - String invokeSignature, boolean isStatic, boolean isNative) { - super(Opcodes.ASM4); - mParentVisitor = mv; - mReturnType = returnType; - mInvokeSignature = invokeSignature; - mIsStatic = isStatic; - mIsNative = isNative; - - if (CONSTRUCTOR.equals(methodName) || CLASS_INIT.equals(methodName)) { - mIsInitMethod = true; - } - } - - private void generateInvoke() { - /* Generates the code: - * OverrideMethod.invoke("signature", mIsNative ? true : false, null or this); - */ - mParentVisitor.visitLdcInsn(mInvokeSignature); - // push true or false - mParentVisitor.visitInsn(mIsNative ? Opcodes.ICONST_1 : Opcodes.ICONST_0); - // push null or this - if (mIsStatic) { - mParentVisitor.visitInsn(Opcodes.ACONST_NULL); - } else { - mParentVisitor.visitVarInsn(Opcodes.ALOAD, 0); - } - - int sort = mReturnType != null ? mReturnType.getSort() : Type.VOID; - switch(sort) { - case Type.VOID: - mParentVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, - "com/android/tools/layoutlib/create/OverrideMethod", - "invokeV", - "(Ljava/lang/String;ZLjava/lang/Object;)V"); - mParentVisitor.visitInsn(Opcodes.RETURN); - break; - case Type.BOOLEAN: - case Type.CHAR: - case Type.BYTE: - case Type.SHORT: - case Type.INT: - mParentVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, - "com/android/tools/layoutlib/create/OverrideMethod", - "invokeI", - "(Ljava/lang/String;ZLjava/lang/Object;)I"); - switch(sort) { - case Type.BOOLEAN: - Label l1 = new Label(); - mParentVisitor.visitJumpInsn(Opcodes.IFEQ, l1); - mParentVisitor.visitInsn(Opcodes.ICONST_1); - mParentVisitor.visitInsn(Opcodes.IRETURN); - mParentVisitor.visitLabel(l1); - mParentVisitor.visitInsn(Opcodes.ICONST_0); - break; - case Type.CHAR: - mParentVisitor.visitInsn(Opcodes.I2C); - break; - case Type.BYTE: - mParentVisitor.visitInsn(Opcodes.I2B); - break; - case Type.SHORT: - mParentVisitor.visitInsn(Opcodes.I2S); - break; - } - mParentVisitor.visitInsn(Opcodes.IRETURN); - break; - case Type.LONG: - mParentVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, - "com/android/tools/layoutlib/create/OverrideMethod", - "invokeL", - "(Ljava/lang/String;ZLjava/lang/Object;)J"); - mParentVisitor.visitInsn(Opcodes.LRETURN); - break; - case Type.FLOAT: - mParentVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, - "com/android/tools/layoutlib/create/OverrideMethod", - "invokeF", - "(Ljava/lang/String;ZLjava/lang/Object;)F"); - mParentVisitor.visitInsn(Opcodes.FRETURN); - break; - case Type.DOUBLE: - mParentVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, - "com/android/tools/layoutlib/create/OverrideMethod", - "invokeD", - "(Ljava/lang/String;ZLjava/lang/Object;)D"); - mParentVisitor.visitInsn(Opcodes.DRETURN); - break; - case Type.ARRAY: - case Type.OBJECT: - mParentVisitor.visitMethodInsn(Opcodes.INVOKESTATIC, - "com/android/tools/layoutlib/create/OverrideMethod", - "invokeA", - "(Ljava/lang/String;ZLjava/lang/Object;)Ljava/lang/Object;"); - mParentVisitor.visitTypeInsn(Opcodes.CHECKCAST, mReturnType.getInternalName()); - mParentVisitor.visitInsn(Opcodes.ARETURN); - break; - } - - } - - private void generatePop() { - /* Pops the stack, depending on the return type. - */ - switch(mReturnType != null ? mReturnType.getSort() : Type.VOID) { - case Type.VOID: - break; - case Type.BOOLEAN: - case Type.CHAR: - case Type.BYTE: - case Type.SHORT: - case Type.INT: - case Type.FLOAT: - case Type.ARRAY: - case Type.OBJECT: - mParentVisitor.visitInsn(Opcodes.POP); - break; - case Type.LONG: - case Type.DOUBLE: - mParentVisitor.visitInsn(Opcodes.POP2); - break; - } - } - - /* Pass down to visitor writer. In this implementation, either do nothing. */ - @Override - public void visitCode() { - mParentVisitor.visitCode(); - } - - /* - * visitMaxs is called just before visitEnd if there was any code to rewrite. - * For non-constructor, generate the messaging code and the return statement - * if it hasn't been done before. - */ - @Override - public void visitMaxs(int maxStack, int maxLocals) { - if (!mIsInitMethod && !mMessageGenerated) { - generateInvoke(); - mMessageGenerated = true; - } - mParentVisitor.visitMaxs(maxStack, maxLocals); - } - - /** - * End of visiting. - * For non-constructor, generate the messaging code and the return statement - * if it hasn't been done before. - */ - @Override - public void visitEnd() { - if (!mIsInitMethod && !mMessageGenerated) { - generateInvoke(); - mMessageGenerated = true; - mParentVisitor.visitMaxs(1, 1); - } - mParentVisitor.visitEnd(); - } - - /* Writes all annotation from the original method. */ - @Override - public AnnotationVisitor visitAnnotation(String desc, boolean visible) { - return mParentVisitor.visitAnnotation(desc, visible); - } - - /* Writes all annotation default values from the original method. */ - @Override - public AnnotationVisitor visitAnnotationDefault() { - return mParentVisitor.visitAnnotationDefault(); - } - - @Override - public AnnotationVisitor visitParameterAnnotation(int parameter, String desc, - boolean visible) { - return mParentVisitor.visitParameterAnnotation(parameter, desc, visible); - } - - /* Writes all attributes from the original method. */ - @Override - public void visitAttribute(Attribute attr) { - mParentVisitor.visitAttribute(attr); - } - - /* - * Only writes the first line number present in the original code so that source - * viewers can direct to the correct method, even if the content doesn't match. - */ - @Override - public void visitLineNumber(int line, Label start) { - if (mIsInitMethod || mOutputFirstLineNumber) { - mParentVisitor.visitLineNumber(line, start); - mOutputFirstLineNumber = false; - } - } - - /** - * For non-constructor, rewrite existing "return" instructions to write the message. - */ - @Override - public void visitInsn(int opcode) { - if (mIsInitMethod) { - switch (opcode) { - case Opcodes.RETURN: - case Opcodes.ARETURN: - case Opcodes.DRETURN: - case Opcodes.FRETURN: - case Opcodes.IRETURN: - case Opcodes.LRETURN: - // Pop the last word from the stack since invoke will generate its own return. - generatePop(); - generateInvoke(); - mMessageGenerated = true; - //$FALL-THROUGH$ - default: - mParentVisitor.visitInsn(opcode); - } - } - } - - @Override - public void visitLabel(Label label) { - if (mIsInitMethod) { - mParentVisitor.visitLabel(label); - } - } - - @Override - public void visitTryCatchBlock(Label start, Label end, Label handler, String type) { - if (mIsInitMethod) { - mParentVisitor.visitTryCatchBlock(start, end, handler, type); - } - } - - @Override - public void visitMethodInsn(int opcode, String owner, String name, String desc) { - if (mIsInitMethod) { - mParentVisitor.visitMethodInsn(opcode, owner, name, desc); - } - } - - @Override - public void visitFieldInsn(int opcode, String owner, String name, String desc) { - if (mIsInitMethod) { - mParentVisitor.visitFieldInsn(opcode, owner, name, desc); - } - } - - @Override - public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) { - if (mIsInitMethod) { - mParentVisitor.visitFrame(type, nLocal, local, nStack, stack); - } - } - - @Override - public void visitIincInsn(int var, int increment) { - if (mIsInitMethod) { - mParentVisitor.visitIincInsn(var, increment); - } - } - - @Override - public void visitIntInsn(int opcode, int operand) { - if (mIsInitMethod) { - mParentVisitor.visitIntInsn(opcode, operand); - } - } - - @Override - public void visitJumpInsn(int opcode, Label label) { - if (mIsInitMethod) { - mParentVisitor.visitJumpInsn(opcode, label); - } - } - - @Override - public void visitLdcInsn(Object cst) { - if (mIsInitMethod) { - mParentVisitor.visitLdcInsn(cst); - } - } - - @Override - public void visitLocalVariable(String name, String desc, String signature, - Label start, Label end, int index) { - if (mIsInitMethod) { - mParentVisitor.visitLocalVariable(name, desc, signature, start, end, index); - } - } - - @Override - public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) { - if (mIsInitMethod) { - mParentVisitor.visitLookupSwitchInsn(dflt, keys, labels); - } - } - - @Override - public void visitMultiANewArrayInsn(String desc, int dims) { - if (mIsInitMethod) { - mParentVisitor.visitMultiANewArrayInsn(desc, dims); - } - } - - @Override - public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels) { - if (mIsInitMethod) { - mParentVisitor.visitTableSwitchInsn(min, max, dflt, labels); - } - } - - @Override - public void visitTypeInsn(int opcode, String type) { - if (mIsInitMethod) { - mParentVisitor.visitTypeInsn(opcode, type); - } - } - - @Override - public void visitVarInsn(int opcode, int var) { - if (mIsInitMethod) { - mParentVisitor.visitVarInsn(opcode, var); - } - } - -} diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/TransformClassAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/TransformClassAdapter.java deleted file mode 100644 index d45a183..0000000 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/TransformClassAdapter.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (C) 2008 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.layoutlib.create; - -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.FieldVisitor; -import org.objectweb.asm.MethodVisitor; -import org.objectweb.asm.Opcodes; -import org.objectweb.asm.Type; - -import java.util.Set; - -/** - * Class adapter that can stub some or all of the methods of the class. - */ -class TransformClassAdapter extends ClassVisitor { - - /** True if all methods should be stubbed, false if only native ones must be stubbed. */ - private final boolean mStubAll; - /** True if the class is an interface. */ - private boolean mIsInterface; - private final String mClassName; - private final Log mLog; - private final Set<String> mStubMethods; - private Set<String> mDeleteReturns; - - /** - * Creates a new class adapter that will stub some or all methods. - * @param logger - * @param stubMethods list of method signatures to always stub out - * @param deleteReturns list of types that trigger the deletion of methods returning them. - * @param className The name of the class being modified - * @param cv The parent class writer visitor - * @param stubNativesOnly True if only native methods should be stubbed. False if all - * methods should be stubbed. - * @param hasNative True if the method has natives, in which case its access should be - * changed. - */ - public TransformClassAdapter(Log logger, Set<String> stubMethods, - Set<String> deleteReturns, String className, ClassVisitor cv, - boolean stubNativesOnly, boolean hasNative) { - super(Opcodes.ASM4, cv); - mLog = logger; - mStubMethods = stubMethods; - mClassName = className; - mStubAll = !stubNativesOnly; - mIsInterface = false; - mDeleteReturns = deleteReturns; - } - - /* Visits the class header. */ - @Override - public void visit(int version, int access, String name, - String signature, String superName, String[] interfaces) { - - // This class might be being renamed. - name = mClassName; - - // remove protected or private and set as public - if (Main.sOptions.generatePublicAccess) { - access = access & ~(Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED); - access |= Opcodes.ACC_PUBLIC; - } - // remove final - access = access & ~Opcodes.ACC_FINAL; - // note: leave abstract classes as such - // don't try to implement stub for interfaces - - mIsInterface = ((access & Opcodes.ACC_INTERFACE) != 0); - super.visit(version, access, name, signature, superName, interfaces); - } - - /* Visits the header of an inner class. */ - @Override - public void visitInnerClass(String name, String outerName, String innerName, int access) { - // remove protected or private and set as public - if (Main.sOptions.generatePublicAccess) { - access = access & ~(Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED); - access |= Opcodes.ACC_PUBLIC; - } - // remove final - access = access & ~Opcodes.ACC_FINAL; - // note: leave abstract classes as such - // don't try to implement stub for interfaces - - super.visitInnerClass(name, outerName, innerName, access); - } - - /* Visits a method. */ - @Override - public MethodVisitor visitMethod(int access, String name, String desc, - String signature, String[] exceptions) { - - if (mDeleteReturns != null) { - Type t = Type.getReturnType(desc); - if (t.getSort() == Type.OBJECT) { - String returnType = t.getInternalName(); - if (returnType != null) { - if (mDeleteReturns.contains(returnType)) { - return null; - } - } - } - } - - String methodSignature = mClassName.replace('/', '.') + "#" + name; - - // change access to public - if (Main.sOptions.generatePublicAccess) { - access &= ~(Opcodes.ACC_PROTECTED | Opcodes.ACC_PRIVATE); - access |= Opcodes.ACC_PUBLIC; - } - - // remove final - access = access & ~Opcodes.ACC_FINAL; - - // stub this method if they are all to be stubbed or if it is a native method - // and don't try to stub interfaces nor abstract non-native methods. - if (!mIsInterface && - ((access & (Opcodes.ACC_ABSTRACT | Opcodes.ACC_NATIVE)) != Opcodes.ACC_ABSTRACT) && - (mStubAll || - (access & Opcodes.ACC_NATIVE) != 0) || - mStubMethods.contains(methodSignature)) { - - boolean isStatic = (access & Opcodes.ACC_STATIC) != 0; - boolean isNative = (access & Opcodes.ACC_NATIVE) != 0; - - // remove abstract, final and native - access = access & ~(Opcodes.ACC_ABSTRACT | Opcodes.ACC_FINAL | Opcodes.ACC_NATIVE); - - String invokeSignature = methodSignature + desc; - mLog.debug(" Stub: %s (%s)", invokeSignature, isNative ? "native" : ""); - - MethodVisitor mw = super.visitMethod(access, name, desc, signature, exceptions); - return new StubMethodAdapter(mw, name, returnType(desc), invokeSignature, - isStatic, isNative); - - } else { - mLog.debug(" Keep: %s %s", name, desc); - return super.visitMethod(access, name, desc, signature, exceptions); - } - } - - /* Visits a field. Makes it public. */ - @Override - public FieldVisitor visitField(int access, String name, String desc, String signature, - Object value) { - // change access to public - if (Main.sOptions.generatePublicAccess) { - access &= ~(Opcodes.ACC_PROTECTED | Opcodes.ACC_PRIVATE); - access |= Opcodes.ACC_PUBLIC; - } - return super.visitField(access, name, desc, signature, value); - } - - /** - * Extracts the return {@link Type} of this descriptor. - */ - Type returnType(String desc) { - if (desc != null) { - try { - return Type.getReturnType(desc); - } catch (ArrayIndexOutOfBoundsException e) { - // ignore, not a valid type. - } - } - return null; - } -} diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java deleted file mode 100644 index d6dba6a..0000000 --- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * Copyright (C) 2008 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.layoutlib.create; - -import static org.junit.Assert.assertArrayEquals; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - -import com.android.tools.layoutlib.create.AsmAnalyzer.DependencyVisitor; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.objectweb.asm.ClassReader; - -import java.io.IOException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Map; -import java.util.TreeMap; - -/** - * Unit tests for some methods of {@link AsmAnalyzer}. - */ -public class AsmAnalyzerTest { - - private MockLog mLog; - private ArrayList<String> mOsJarPath; - private AsmAnalyzer mAa; - - @Before - public void setUp() throws Exception { - mLog = new MockLog(); - URL url = this.getClass().getClassLoader().getResource("data/mock_android.jar"); - - mOsJarPath = new ArrayList<String>(); - mOsJarPath.add(url.getFile()); - - mAa = new AsmAnalyzer(mLog, mOsJarPath, null /* gen */, - null /* deriveFrom */, null /* includeGlobs */ ); - } - - @After - public void tearDown() throws Exception { - } - - @Test - public void testParseZip() throws IOException { - Map<String, ClassReader> map = mAa.parseZip(mOsJarPath); - - assertArrayEquals(new String[] { - "mock_android.dummy.InnerTest", - "mock_android.dummy.InnerTest$DerivingClass", - "mock_android.dummy.InnerTest$MyGenerics1", - "mock_android.dummy.InnerTest$MyIntEnum", - "mock_android.dummy.InnerTest$MyStaticInnerClass", - "mock_android.dummy.InnerTest$NotStaticInner1", - "mock_android.dummy.InnerTest$NotStaticInner2", - "mock_android.view.View", - "mock_android.view.ViewGroup", - "mock_android.view.ViewGroup$LayoutParams", - "mock_android.view.ViewGroup$MarginLayoutParams", - "mock_android.widget.LinearLayout", - "mock_android.widget.LinearLayout$LayoutParams", - "mock_android.widget.TableLayout", - "mock_android.widget.TableLayout$LayoutParams" - }, - map.keySet().toArray()); - } - - @Test - public void testFindClass() throws IOException, LogAbortException { - Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath); - TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>(); - - ClassReader cr = mAa.findClass("mock_android.view.ViewGroup$LayoutParams", - zipClasses, found); - - assertNotNull(cr); - assertEquals("mock_android/view/ViewGroup$LayoutParams", cr.getClassName()); - assertArrayEquals(new String[] { "mock_android.view.ViewGroup$LayoutParams" }, - found.keySet().toArray()); - assertArrayEquals(new ClassReader[] { cr }, found.values().toArray()); - } - - @Test - public void testFindGlobs() throws IOException, LogAbortException { - Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath); - TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>(); - - // this matches classes, a package match returns nothing - found.clear(); - mAa.findGlobs("mock_android.view", zipClasses, found); - - assertArrayEquals(new String[] { }, - found.keySet().toArray()); - - // a complex glob search. * is a search pattern that matches names, not dots - mAa.findGlobs("mock_android.*.*Group$*Layout*", zipClasses, found); - - assertArrayEquals(new String[] { - "mock_android.view.ViewGroup$LayoutParams", - "mock_android.view.ViewGroup$MarginLayoutParams" - }, - found.keySet().toArray()); - - // a complex glob search. ** is a search pattern that matches names including dots - mAa.findGlobs("mock_android.**Group*", zipClasses, found); - - assertArrayEquals(new String[] { - "mock_android.view.ViewGroup", - "mock_android.view.ViewGroup$LayoutParams", - "mock_android.view.ViewGroup$MarginLayoutParams" - }, - found.keySet().toArray()); - - // matches a single class - found.clear(); - mAa.findGlobs("mock_android.view.View", zipClasses, found); - - assertArrayEquals(new String[] { - "mock_android.view.View" - }, - found.keySet().toArray()); - - // matches everyting inside the given package but not sub-packages - found.clear(); - mAa.findGlobs("mock_android.view.*", zipClasses, found); - - assertArrayEquals(new String[] { - "mock_android.view.View", - "mock_android.view.ViewGroup", - "mock_android.view.ViewGroup$LayoutParams", - "mock_android.view.ViewGroup$MarginLayoutParams" - }, - found.keySet().toArray()); - - for (String key : found.keySet()) { - ClassReader value = found.get(key); - assertNotNull("No value for " + key, value); - assertEquals(key, AsmAnalyzer.classReaderToClassName(value)); - } - } - - @Test - public void testFindClassesDerivingFrom() throws LogAbortException, IOException { - Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath); - TreeMap<String, ClassReader> found = new TreeMap<String, ClassReader>(); - - mAa.findClassesDerivingFrom("mock_android.view.View", zipClasses, found); - - assertArrayEquals(new String[] { - "mock_android.view.View", - "mock_android.view.ViewGroup", - "mock_android.widget.LinearLayout", - "mock_android.widget.TableLayout", - }, - found.keySet().toArray()); - - for (String key : found.keySet()) { - ClassReader value = found.get(key); - assertNotNull("No value for " + key, value); - assertEquals(key, AsmAnalyzer.classReaderToClassName(value)); - } - } - - @Test - public void testDependencyVisitor() throws IOException, LogAbortException { - Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath); - TreeMap<String, ClassReader> keep = new TreeMap<String, ClassReader>(); - TreeMap<String, ClassReader> new_keep = new TreeMap<String, ClassReader>(); - TreeMap<String, ClassReader> in_deps = new TreeMap<String, ClassReader>(); - TreeMap<String, ClassReader> out_deps = new TreeMap<String, ClassReader>(); - - ClassReader cr = mAa.findClass("mock_android.widget.TableLayout", zipClasses, keep); - DependencyVisitor visitor = mAa.getVisitor(zipClasses, keep, new_keep, in_deps, out_deps); - - // get first level dependencies - cr.accept(visitor, 0 /* flags */); - - assertArrayEquals(new String[] { - "mock_android.view.ViewGroup", - "mock_android.widget.TableLayout$LayoutParams", - }, - out_deps.keySet().toArray()); - - in_deps.putAll(out_deps); - out_deps.clear(); - - // get second level dependencies - for (ClassReader cr2 : in_deps.values()) { - cr2.accept(visitor, 0 /* flags */); - } - - assertArrayEquals(new String[] { - "mock_android.view.View", - "mock_android.view.ViewGroup$LayoutParams", - "mock_android.view.ViewGroup$MarginLayoutParams", - }, - out_deps.keySet().toArray()); - - in_deps.putAll(out_deps); - out_deps.clear(); - - // get third level dependencies (there are none) - for (ClassReader cr2 : in_deps.values()) { - cr2.accept(visitor, 0 /* flags */); - } - - assertArrayEquals(new String[] { }, out_deps.keySet().toArray()); - } -} diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java deleted file mode 100644 index 7b76a5b..0000000 --- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java +++ /dev/null @@ -1,119 +0,0 @@ -/* - * Copyright (C) 2008 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.layoutlib.create; - - -import static org.junit.Assert.assertArrayEquals; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import java.io.File; -import java.io.IOException; -import java.net.URL; -import java.util.ArrayList; -import java.util.Set; - -/** - * Unit tests for some methods of {@link AsmGenerator}. - */ -public class AsmGeneratorTest { - - private MockLog mLog; - private ArrayList<String> mOsJarPath; - private String mOsDestJar; - private File mTempFile; - - @Before - public void setUp() throws Exception { - mLog = new MockLog(); - URL url = this.getClass().getClassLoader().getResource("data/mock_android.jar"); - - mOsJarPath = new ArrayList<String>(); - mOsJarPath.add(url.getFile()); - - mTempFile = File.createTempFile("mock", "jar"); - mOsDestJar = mTempFile.getAbsolutePath(); - mTempFile.deleteOnExit(); - } - - @After - public void tearDown() throws Exception { - if (mTempFile != null) { - mTempFile.delete(); - mTempFile = null; - } - } - - @Test - public void testClassRenaming() throws IOException, LogAbortException { - - ICreateInfo ci = new ICreateInfo() { - @Override - public Class<?>[] getInjectedClasses() { - // classes to inject in the final JAR - return new Class<?>[0]; - } - - @Override - public String[] getDelegateMethods() { - return new String[0]; - } - - @Override - public String[] getDelegateClassNatives() { - return new String[0]; - } - - @Override - public String[] getOverriddenMethods() { - // methods to force override - return new String[0]; - } - - @Override - public String[] getRenamedClasses() { - // classes to rename (so that we can replace them) - return new String[] { - "mock_android.view.View", "mock_android.view._Original_View", - "not.an.actual.ClassName", "anoter.fake.NewClassName", - }; - } - - @Override - public String[] getDeleteReturns() { - // methods deleted from their return type. - return new String[0]; - } - }; - - AsmGenerator agen = new AsmGenerator(mLog, mOsDestJar, ci); - - AsmAnalyzer aa = new AsmAnalyzer(mLog, mOsJarPath, agen, - null, // derived from - new String[] { // include classes - "**" - }); - aa.analyze(); - agen.generate(); - - Set<String> notRenamed = agen.getClassesNotRenamed(); - assertArrayEquals(new String[] { "not/an/actual/ClassName" }, notRenamed.toArray()); - } -} diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/ClassHasNativeVisitorTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/ClassHasNativeVisitorTest.java deleted file mode 100644 index 0135c40..0000000 --- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/ClassHasNativeVisitorTest.java +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (C) 2010 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.layoutlib.create; - -import static org.junit.Assert.*; - -import org.junit.Test; -import org.objectweb.asm.ClassReader; - -import java.io.IOException; -import java.util.ArrayList; - - -/** - * Tests {@link ClassHasNativeVisitor}. - */ -public class ClassHasNativeVisitorTest { - - @Test - public void testHasNative() throws IOException { - MockClassHasNativeVisitor cv = new MockClassHasNativeVisitor(); - String className = - this.getClass().getCanonicalName() + "$" + ClassWithNative.class.getSimpleName(); - ClassReader cr = new ClassReader(className); - - cr.accept(cv, 0 /* flags */); - assertArrayEquals(new String[] { "native_method" }, cv.getMethodsFound()); - assertTrue(cv.hasNativeMethods()); - } - - @Test - public void testHasNoNative() throws IOException { - MockClassHasNativeVisitor cv = new MockClassHasNativeVisitor(); - String className = - this.getClass().getCanonicalName() + "$" + ClassWithoutNative.class.getSimpleName(); - ClassReader cr = new ClassReader(className); - - cr.accept(cv, 0 /* flags */); - assertArrayEquals(new String[0], cv.getMethodsFound()); - assertFalse(cv.hasNativeMethods()); - } - - //------- - - /** - * Overrides {@link ClassHasNativeVisitor} to collec the name of the native methods found. - */ - private static class MockClassHasNativeVisitor extends ClassHasNativeVisitor { - private ArrayList<String> mMethodsFound = new ArrayList<String>(); - - public String[] getMethodsFound() { - return mMethodsFound.toArray(new String[mMethodsFound.size()]); - } - - @Override - protected void setHasNativeMethods(boolean hasNativeMethods, String methodName) { - if (hasNativeMethods) { - mMethodsFound.add(methodName); - } - super.setHasNativeMethods(hasNativeMethods, methodName); - } - } - - /** - * Dummy test class with a native method. - */ - public static class ClassWithNative { - public ClassWithNative() { - } - - public void callTheNativeMethod() { - native_method(); - } - - private native void native_method(); - } - - /** - * Dummy test class with no native method. - */ - public static class ClassWithoutNative { - public ClassWithoutNative() { - } - - public void someMethod() { - } - } -} diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java deleted file mode 100644 index 6e120ce..0000000 --- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java +++ /dev/null @@ -1,463 +0,0 @@ -/* - * Copyright (C) 2010 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.layoutlib.create; - - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -import com.android.tools.layoutlib.create.dataclass.ClassWithNative; -import com.android.tools.layoutlib.create.dataclass.OuterClass; -import com.android.tools.layoutlib.create.dataclass.OuterClass.InnerClass; - -import org.junit.Before; -import org.junit.Test; -import org.objectweb.asm.ClassReader; -import org.objectweb.asm.ClassVisitor; -import org.objectweb.asm.ClassWriter; - -import java.io.IOException; -import java.io.PrintWriter; -import java.io.StringWriter; -import java.lang.annotation.Annotation; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -public class DelegateClassAdapterTest { - - private MockLog mLog; - - private static final String NATIVE_CLASS_NAME = ClassWithNative.class.getCanonicalName(); - private static final String OUTER_CLASS_NAME = OuterClass.class.getCanonicalName(); - private static final String INNER_CLASS_NAME = OuterClass.class.getCanonicalName() + "$" + - InnerClass.class.getSimpleName(); - - @Before - public void setUp() throws Exception { - mLog = new MockLog(); - mLog.setVerbose(true); // capture debug error too - } - - /** - * Tests that a class not being modified still works. - */ - @SuppressWarnings("unchecked") - @Test - public void testNoOp() throws Throwable { - // create an instance of the class that will be modified - // (load the class in a distinct class loader so that we can trash its definition later) - ClassLoader cl1 = new ClassLoader(this.getClass().getClassLoader()) { }; - Class<ClassWithNative> clazz1 = (Class<ClassWithNative>) cl1.loadClass(NATIVE_CLASS_NAME); - ClassWithNative instance1 = clazz1.newInstance(); - assertEquals(42, instance1.add(20, 22)); - try { - instance1.callNativeInstance(10, 3.1415, new Object[0] ); - fail("Test should have failed to invoke callTheNativeMethod [1]"); - } catch (UnsatisfiedLinkError e) { - // This is expected to fail since the native method is not implemented. - } - - // Now process it but tell the delegate to not modify any method - ClassWriter cw = new ClassWriter(0 /*flags*/); - - HashSet<String> delegateMethods = new HashSet<String>(); - String internalClassName = NATIVE_CLASS_NAME.replace('.', '/'); - DelegateClassAdapter cv = new DelegateClassAdapter( - mLog, cw, internalClassName, delegateMethods); - - ClassReader cr = new ClassReader(NATIVE_CLASS_NAME); - cr.accept(cv, 0 /* flags */); - - // Load the generated class in a different class loader and try it again - - ClassLoader2 cl2 = null; - try { - cl2 = new ClassLoader2() { - @Override - public void testModifiedInstance() throws Exception { - Class<?> clazz2 = loadClass(NATIVE_CLASS_NAME); - Object i2 = clazz2.newInstance(); - assertNotNull(i2); - assertEquals(42, callAdd(i2, 20, 22)); - - try { - callCallNativeInstance(i2, 10, 3.1415, new Object[0]); - fail("Test should have failed to invoke callTheNativeMethod [2]"); - } catch (InvocationTargetException e) { - // This is expected to fail since the native method has NOT been - // overridden here. - assertEquals(UnsatisfiedLinkError.class, e.getCause().getClass()); - } - - // Check that the native method does NOT have the new annotation - Method[] m = clazz2.getDeclaredMethods(); - assertEquals("native_instance", m[2].getName()); - assertTrue(Modifier.isNative(m[2].getModifiers())); - Annotation[] a = m[2].getAnnotations(); - assertEquals(0, a.length); - } - }; - cl2.add(NATIVE_CLASS_NAME, cw); - cl2.testModifiedInstance(); - } catch (Throwable t) { - throw dumpGeneratedClass(t, cl2); - } - } - - /** - * {@link DelegateMethodAdapter2} does not support overriding constructors yet, - * so this should fail with an {@link UnsupportedOperationException}. - * - * Although not tested here, the message of the exception should contain the - * constructor signature. - */ - @Test(expected=UnsupportedOperationException.class) - public void testConstructorsNotSupported() throws IOException { - ClassWriter cw = new ClassWriter(0 /*flags*/); - - String internalClassName = NATIVE_CLASS_NAME.replace('.', '/'); - - HashSet<String> delegateMethods = new HashSet<String>(); - delegateMethods.add("<init>"); - DelegateClassAdapter cv = new DelegateClassAdapter( - mLog, cw, internalClassName, delegateMethods); - - ClassReader cr = new ClassReader(NATIVE_CLASS_NAME); - cr.accept(cv, 0 /* flags */); - } - - @Test - public void testDelegateNative() throws Throwable { - ClassWriter cw = new ClassWriter(0 /*flags*/); - String internalClassName = NATIVE_CLASS_NAME.replace('.', '/'); - - HashSet<String> delegateMethods = new HashSet<String>(); - delegateMethods.add(DelegateClassAdapter.ALL_NATIVES); - DelegateClassAdapter cv = new DelegateClassAdapter( - mLog, cw, internalClassName, delegateMethods); - - ClassReader cr = new ClassReader(NATIVE_CLASS_NAME); - cr.accept(cv, 0 /* flags */); - - // Load the generated class in a different class loader and try it - ClassLoader2 cl2 = null; - try { - cl2 = new ClassLoader2() { - @Override - public void testModifiedInstance() throws Exception { - Class<?> clazz2 = loadClass(NATIVE_CLASS_NAME); - Object i2 = clazz2.newInstance(); - assertNotNull(i2); - - // Use reflection to access inner methods - assertEquals(42, callAdd(i2, 20, 22)); - - Object[] objResult = new Object[] { null }; - int result = callCallNativeInstance(i2, 10, 3.1415, objResult); - assertEquals((int)(10 + 3.1415), result); - assertSame(i2, objResult[0]); - - // Check that the native method now has the new annotation and is not native - Method[] m = clazz2.getDeclaredMethods(); - assertEquals("native_instance", m[2].getName()); - assertFalse(Modifier.isNative(m[2].getModifiers())); - Annotation[] a = m[2].getAnnotations(); - assertEquals("LayoutlibDelegate", a[0].annotationType().getSimpleName()); - } - }; - cl2.add(NATIVE_CLASS_NAME, cw); - cl2.testModifiedInstance(); - } catch (Throwable t) { - throw dumpGeneratedClass(t, cl2); - } - } - - @Test - public void testDelegateInner() throws Throwable { - // We'll delegate the "get" method of both the inner and outer class. - HashSet<String> delegateMethods = new HashSet<String>(); - delegateMethods.add("get"); - delegateMethods.add("privateMethod"); - - // Generate the delegate for the outer class. - ClassWriter cwOuter = new ClassWriter(0 /*flags*/); - String outerClassName = OUTER_CLASS_NAME.replace('.', '/'); - DelegateClassAdapter cvOuter = new DelegateClassAdapter( - mLog, cwOuter, outerClassName, delegateMethods); - ClassReader cr = new ClassReader(OUTER_CLASS_NAME); - cr.accept(cvOuter, 0 /* flags */); - - // Generate the delegate for the inner class. - ClassWriter cwInner = new ClassWriter(0 /*flags*/); - String innerClassName = INNER_CLASS_NAME.replace('.', '/'); - DelegateClassAdapter cvInner = new DelegateClassAdapter( - mLog, cwInner, innerClassName, delegateMethods); - cr = new ClassReader(INNER_CLASS_NAME); - cr.accept(cvInner, 0 /* flags */); - - // Load the generated classes in a different class loader and try them - ClassLoader2 cl2 = null; - try { - cl2 = new ClassLoader2() { - @Override - public void testModifiedInstance() throws Exception { - - // Check the outer class - Class<?> outerClazz2 = loadClass(OUTER_CLASS_NAME); - Object o2 = outerClazz2.newInstance(); - assertNotNull(o2); - - // The original Outer.get returns 1+10+20, - // but the delegate makes it return 4+10+20 - assertEquals(4+10+20, callGet(o2, 10, 20)); - assertEquals(1+10+20, callGet_Original(o2, 10, 20)); - - // The original Outer has a private method that is - // delegated. We should be able to call both the delegate - // and the original (which is now public). - assertEquals("outerPrivateMethod", - callMethod(o2, "privateMethod_Original", false /*makePublic*/)); - - // The original method is private, so by default we can't access it - boolean gotIllegalAccessException = false; - try { - callMethod(o2, "privateMethod", false /*makePublic*/); - } catch(IllegalAccessException e) { - gotIllegalAccessException = true; - } - assertTrue(gotIllegalAccessException); - // Try again, but now making it accessible - assertEquals("outerPrivate_Delegate", - callMethod(o2, "privateMethod", true /*makePublic*/)); - - // Check the inner class. Since it's not a static inner class, we need - // to use the hidden constructor that takes the outer class as first parameter. - Class<?> innerClazz2 = loadClass(INNER_CLASS_NAME); - Constructor<?> innerCons = innerClazz2.getConstructor( - new Class<?>[] { outerClazz2 }); - Object i2 = innerCons.newInstance(new Object[] { o2 }); - assertNotNull(i2); - - // The original Inner.get returns 3+10+20, - // but the delegate makes it return 6+10+20 - assertEquals(6+10+20, callGet(i2, 10, 20)); - assertEquals(3+10+20, callGet_Original(i2, 10, 20)); - } - }; - cl2.add(OUTER_CLASS_NAME, cwOuter.toByteArray()); - cl2.add(INNER_CLASS_NAME, cwInner.toByteArray()); - cl2.testModifiedInstance(); - } catch (Throwable t) { - throw dumpGeneratedClass(t, cl2); - } - } - - //------- - - /** - * A class loader than can define and instantiate our modified classes. - * <p/> - * The trick here is that this class loader will test our <em>modified</em> version - * of the classes, the one with the delegate calls. - * <p/> - * Trying to do so in the original class loader generates all sort of link issues because - * there are 2 different definitions of the same class name. This class loader will - * define and load the class when requested by name and provide helpers to access the - * instance methods via reflection. - */ - private abstract class ClassLoader2 extends ClassLoader { - - private final Map<String, byte[]> mClassDefs = new HashMap<String, byte[]>(); - - public ClassLoader2() { - super(null); - } - - public ClassLoader2 add(String className, byte[] definition) { - mClassDefs.put(className, definition); - return this; - } - - public ClassLoader2 add(String className, ClassWriter rewrittenClass) { - mClassDefs.put(className, rewrittenClass.toByteArray()); - return this; - } - - private Set<Entry<String, byte[]>> getByteCode() { - return mClassDefs.entrySet(); - } - - @SuppressWarnings("unused") - @Override - protected Class<?> findClass(String name) throws ClassNotFoundException { - try { - return super.findClass(name); - } catch (ClassNotFoundException e) { - - byte[] def = mClassDefs.get(name); - if (def != null) { - // Load the modified ClassWithNative from its bytes representation. - return defineClass(name, def, 0, def.length); - } - - try { - // Load everything else from the original definition into the new class loader. - ClassReader cr = new ClassReader(name); - ClassWriter cw = new ClassWriter(0); - cr.accept(cw, 0); - byte[] bytes = cw.toByteArray(); - return defineClass(name, bytes, 0, bytes.length); - - } catch (IOException ioe) { - throw new RuntimeException(ioe); - } - } - } - - /** - * Accesses {@link OuterClass#get} or {@link InnerClass#get}via reflection. - */ - public int callGet(Object instance, int a, long b) throws Exception { - Method m = instance.getClass().getMethod("get", - new Class<?>[] { int.class, long.class } ); - - Object result = m.invoke(instance, new Object[] { a, b }); - return ((Integer) result).intValue(); - } - - /** - * Accesses the "_Original" methods for {@link OuterClass#get} - * or {@link InnerClass#get}via reflection. - */ - public int callGet_Original(Object instance, int a, long b) throws Exception { - Method m = instance.getClass().getMethod("get_Original", - new Class<?>[] { int.class, long.class } ); - - Object result = m.invoke(instance, new Object[] { a, b }); - return ((Integer) result).intValue(); - } - - /** - * Accesses the any declared method that takes no parameter via reflection. - */ - @SuppressWarnings("unchecked") - public <T> T callMethod(Object instance, String methodName, boolean makePublic) throws Exception { - Method m = instance.getClass().getDeclaredMethod(methodName, (Class<?>[])null); - - boolean wasAccessible = m.isAccessible(); - if (makePublic && !wasAccessible) { - m.setAccessible(true); - } - - Object result = m.invoke(instance, (Object[])null); - - if (makePublic && !wasAccessible) { - m.setAccessible(false); - } - - return (T) result; - } - - /** - * Accesses {@link ClassWithNative#add(int, int)} via reflection. - */ - public int callAdd(Object instance, int a, int b) throws Exception { - Method m = instance.getClass().getMethod("add", - new Class<?>[] { int.class, int.class }); - - Object result = m.invoke(instance, new Object[] { a, b }); - return ((Integer) result).intValue(); - } - - /** - * Accesses {@link ClassWithNative#callNativeInstance(int, double, Object[])} - * via reflection. - */ - public int callCallNativeInstance(Object instance, int a, double d, Object[] o) - throws Exception { - Method m = instance.getClass().getMethod("callNativeInstance", - new Class<?>[] { int.class, double.class, Object[].class }); - - Object result = m.invoke(instance, new Object[] { a, d, o }); - return ((Integer) result).intValue(); - } - - public abstract void testModifiedInstance() throws Exception; - } - - /** - * For debugging, it's useful to dump the content of the generated classes - * along with the exception that was generated. - * - * However to make it work you need to pull in the org.objectweb.asm.util.TraceClassVisitor - * class and associated utilities which are found in the ASM source jar. Since we don't - * want that dependency in the source code, we only put it manually for development and - * access the TraceClassVisitor via reflection if present. - * - * @param t The exception thrown by {@link ClassLoader2#testModifiedInstance()} - * @param cl2 The {@link ClassLoader2} instance with the generated bytecode. - * @return Either original {@code t} or a new wrapper {@link Throwable} - */ - private Throwable dumpGeneratedClass(Throwable t, ClassLoader2 cl2) { - try { - // For debugging, dump the bytecode of the class in case of unexpected error - // if we can find the TraceClassVisitor class. - Class<?> tcvClass = Class.forName("org.objectweb.asm.util.TraceClassVisitor"); - - StringBuilder sb = new StringBuilder(); - sb.append('\n').append(t.getClass().getCanonicalName()); - if (t.getMessage() != null) { - sb.append(": ").append(t.getMessage()); - } - - for (Entry<String, byte[]> entry : cl2.getByteCode()) { - String className = entry.getKey(); - byte[] bytes = entry.getValue(); - - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - // next 2 lines do: TraceClassVisitor tcv = new TraceClassVisitor(pw); - Constructor<?> cons = tcvClass.getConstructor(new Class<?>[] { pw.getClass() }); - Object tcv = cons.newInstance(new Object[] { pw }); - ClassReader cr2 = new ClassReader(bytes); - cr2.accept((ClassVisitor) tcv, 0 /* flags */); - - sb.append("\nBytecode dump: <").append(className).append(">:\n") - .append(sw.toString()); - } - - // Re-throw exception with new message - RuntimeException ex = new RuntimeException(sb.toString(), t); - return ex; - } catch (Throwable ignore) { - // In case of problem, just throw the original exception as-is. - return t; - } - } - -} diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/LogTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/LogTest.java deleted file mode 100644 index 1a5f653..0000000 --- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/LogTest.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2008 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.layoutlib.create; - -import static org.junit.Assert.*; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -public class LogTest { - - private MockLog mLog; - - @Before - public void setUp() throws Exception { - mLog = new MockLog(); - } - - @After - public void tearDown() throws Exception { - // pass - } - - @Test - public void testDebug() { - assertEquals("", mLog.getOut()); - assertEquals("", mLog.getErr()); - - mLog.setVerbose(false); - mLog.debug("Test %d", 42); - assertEquals("", mLog.getOut()); - - mLog.setVerbose(true); - mLog.debug("Test %d", 42); - - assertEquals("Test 42\n", mLog.getOut()); - assertEquals("", mLog.getErr()); - } - - @Test - public void testInfo() { - assertEquals("", mLog.getOut()); - assertEquals("", mLog.getErr()); - - mLog.info("Test %d", 43); - - assertEquals("Test 43\n", mLog.getOut()); - assertEquals("", mLog.getErr()); - } - - @Test - public void testError() { - assertEquals("", mLog.getOut()); - assertEquals("", mLog.getErr()); - - mLog.error("Test %d", 44); - - assertEquals("", mLog.getOut()); - assertEquals("Test 44\n", mLog.getErr()); - } - - @Test - public void testException() { - assertEquals("", mLog.getOut()); - assertEquals("", mLog.getErr()); - - Exception e = new Exception("My Exception"); - mLog.exception(e, "Test %d", 44); - - assertEquals("", mLog.getOut()); - assertTrue(mLog.getErr().startsWith("Test 44\njava.lang.Exception: My Exception")); - } -} diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/MockLog.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/MockLog.java deleted file mode 100644 index de750a3..0000000 --- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/MockLog.java +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2010 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.layoutlib.create; - - -public class MockLog extends Log { - StringBuilder mOut = new StringBuilder(); - StringBuilder mErr = new StringBuilder(); - - public String getOut() { - return mOut.toString(); - } - - public String getErr() { - return mErr.toString(); - } - - @Override - protected void outPrintln(String msg) { - mOut.append(msg); - mOut.append('\n'); - } - - @Override - protected void errPrintln(String msg) { - mErr.append(msg); - mErr.append('\n'); - } -} diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/RenameClassAdapterTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/RenameClassAdapterTest.java deleted file mode 100644 index 90c6a9c..0000000 --- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/RenameClassAdapterTest.java +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Copyright (C) 2008 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.layoutlib.create; - -import static org.junit.Assert.*; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -/** - * - */ -public class RenameClassAdapterTest { - - private RenameClassAdapter mOuter; - private RenameClassAdapter mInner; - - @Before - public void setUp() throws Exception { - mOuter = new RenameClassAdapter(null, // cv - "com.pack.Old", - "org.blah.New"); - - mInner = new RenameClassAdapter(null, // cv - "com.pack.Old$Inner", - "org.blah.New$Inner"); - } - - @After - public void tearDown() throws Exception { - } - - /** - * Renames a type, e.g. "Lcom.package.My;" - * If the type doesn't need to be renamed, returns the input string as-is. - */ - @Test - public void testRenameTypeDesc() { - - // primitive types are left untouched - assertEquals("I", mOuter.renameTypeDesc("I")); - assertEquals("D", mOuter.renameTypeDesc("D")); - assertEquals("V", mOuter.renameTypeDesc("V")); - - // object types that need no renaming are left untouched - assertEquals("Lcom.package.MyClass;", mOuter.renameTypeDesc("Lcom.package.MyClass;")); - assertEquals("Lcom.package.MyClass;", mInner.renameTypeDesc("Lcom.package.MyClass;")); - - // object types that match the requirements - assertEquals("Lorg.blah.New;", mOuter.renameTypeDesc("Lcom.pack.Old;")); - assertEquals("Lorg.blah.New$Inner;", mInner.renameTypeDesc("Lcom.pack.Old$Inner;")); - // inner classes match the base type which is being renamed - assertEquals("Lorg.blah.New$Other;", mOuter.renameTypeDesc("Lcom.pack.Old$Other;")); - assertEquals("Lorg.blah.New$Other;", mInner.renameTypeDesc("Lcom.pack.Old$Other;")); - - // arrays - assertEquals("[Lorg.blah.New;", mOuter.renameTypeDesc("[Lcom.pack.Old;")); - assertEquals("[[Lorg.blah.New;", mOuter.renameTypeDesc("[[Lcom.pack.Old;")); - - assertEquals("[Lorg.blah.New;", mInner.renameTypeDesc("[Lcom.pack.Old;")); - assertEquals("[[Lorg.blah.New;", mInner.renameTypeDesc("[[Lcom.pack.Old;")); - } - - /** - * Renames an object type, e.g. "Lcom.package.MyClass;" or an array type that has an - * object element, e.g. "[Lcom.package.MyClass;" - * If the type doesn't need to be renamed, returns the internal name of the input type. - */ - @Test - public void testRenameType() { - // Skip. This is actually tested by testRenameTypeDesc above. - } - - /** - * Renames an internal type name, e.g. "com.package.MyClass". - * If the type doesn't need to be renamed, returns the input string as-is. - */ - @Test - public void testRenameInternalType() { - // a descriptor is not left untouched - assertEquals("Lorg.blah.New;", mOuter.renameInternalType("Lcom.pack.Old;")); - assertEquals("Lorg.blah.New$Inner;", mOuter.renameInternalType("Lcom.pack.Old$Inner;")); - - // an actual FQCN - assertEquals("org.blah.New", mOuter.renameInternalType("com.pack.Old")); - assertEquals("org.blah.New$Inner", mOuter.renameInternalType("com.pack.Old$Inner")); - - assertEquals("org.blah.New$Other", mInner.renameInternalType("com.pack.Old$Other")); - assertEquals("org.blah.New$Other", mInner.renameInternalType("com.pack.Old$Other")); - } - - /** - * Renames a method descriptor, i.e. applies renameType to all arguments and to the - * return value. - */ - @Test - public void testRenameMethodDesc() { - assertEquals("(IDLorg.blah.New;[Lorg.blah.New$Inner;)Lorg.blah.New$Other;", - mOuter.renameMethodDesc("(IDLcom.pack.Old;[Lcom.pack.Old$Inner;)Lcom.pack.Old$Other;")); - } - - - -} diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/ClassWithNative.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/ClassWithNative.java deleted file mode 100644 index c314853..0000000 --- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/ClassWithNative.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2010 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.layoutlib.create.dataclass; - -import com.android.tools.layoutlib.create.DelegateClassAdapterTest; - -/** - * Dummy test class with a native method. - * The native method is not defined and any attempt to invoke it will - * throw an {@link UnsatisfiedLinkError}. - * - * Used by {@link DelegateClassAdapterTest}. - */ -public class ClassWithNative { - public ClassWithNative() { - } - - public int add(int a, int b) { - return a + b; - } - - // Note: it's good to have a long or double for testing parameters since they take - // 2 slots in the stack/locals maps. - - public int callNativeInstance(int a, double d, Object[] o) { - return native_instance(a, d, o); - } - - private native int native_instance(int a, double d, Object[] o); -} - diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/ClassWithNative_Delegate.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/ClassWithNative_Delegate.java deleted file mode 100644 index a3d4dc6..0000000 --- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/ClassWithNative_Delegate.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2010 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.layoutlib.create.dataclass; - -import com.android.tools.layoutlib.create.DelegateClassAdapterTest; - -/** - * The delegate that receives the call to {@link ClassWithNative_Delegate}'s overridden methods. - * - * Used by {@link DelegateClassAdapterTest}. - */ -public class ClassWithNative_Delegate { - public static int native_instance(ClassWithNative instance, int a, double d, Object[] o) { - if (o != null && o.length > 0) { - o[0] = instance; - } - return (int)(a + d); - } -} - diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass.java deleted file mode 100644 index f083e76..0000000 --- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.tools.layoutlib.create.dataclass; - -import com.android.tools.layoutlib.create.DelegateClassAdapterTest; - -/** - * Test class with an inner class. - * - * Used by {@link DelegateClassAdapterTest}. - */ -public class OuterClass { - private int mOuterValue = 1; - public OuterClass() { - } - - // Outer.get returns 1 + a + b - // Note: it's good to have a long or double for testing parameters since they take - // 2 slots in the stack/locals maps. - public int get(int a, long b) { - return mOuterValue + a + (int) b; - } - - public class InnerClass { - public InnerClass() { - } - - // Inner.get returns 2 + 1 + a + b - public int get(int a, long b) { - return 2 + mOuterValue + a + (int) b; - } - } - - @SuppressWarnings("unused") - private String privateMethod() { - return "outerPrivateMethod"; - } -} - diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass_Delegate.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass_Delegate.java deleted file mode 100644 index 774be8e..0000000 --- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass_Delegate.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.tools.layoutlib.create.dataclass; - -import com.android.tools.layoutlib.create.DelegateClassAdapterTest; - -/** - * Used by {@link DelegateClassAdapterTest}. - */ -public class OuterClass_Delegate { - // The delegate override of Outer.get returns 4 + a + b - public static int get(OuterClass instance, int a, long b) { - return 4 + a + (int) b; - } - - public static String privateMethod(OuterClass instance) { - return "outerPrivate_Delegate"; - } -} - diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass_InnerClass_Delegate.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass_InnerClass_Delegate.java deleted file mode 100644 index b472220..0000000 --- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass_InnerClass_Delegate.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.tools.layoutlib.create.dataclass; - -import com.android.tools.layoutlib.create.DelegateClassAdapterTest; -import com.android.tools.layoutlib.create.dataclass.OuterClass.InnerClass; - -/** - * Used by {@link DelegateClassAdapterTest}. - */ -public class OuterClass_InnerClass_Delegate { - // The delegate override of Inner.get return 6 + a + b - public static int get(OuterClass outer, InnerClass inner, int a, long b) { - return 6 + a + (int) b; - } -} diff --git a/tools/layoutlib/create/tests/data/mock_android.jar b/tools/layoutlib/create/tests/data/mock_android.jar Binary files differdeleted file mode 100644 index a7ea74f..0000000 --- a/tools/layoutlib/create/tests/data/mock_android.jar +++ /dev/null diff --git a/tools/layoutlib/create/tests/data/mock_android.jardesc b/tools/layoutlib/create/tests/data/mock_android.jardesc deleted file mode 100644 index 95f7591..0000000 --- a/tools/layoutlib/create/tests/data/mock_android.jardesc +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="WINDOWS-1252" standalone="no"?> -<jardesc> - <jar path="C:/ralf/google/src/raphael-lapdroid/device/tools/layoutlib/create/tests/data/mock_android.jar"/> - <options buildIfNeeded="true" compress="true" descriptionLocation="/layoutlib_create/tests/data/mock_android.jardesc" exportErrors="true" exportWarnings="true" includeDirectoryEntries="false" overwrite="false" saveDescription="true" storeRefactorings="false" useSourceFolders="false"/> - <storedRefactorings deprecationInfo="true" structuralOnly="false"/> - <selectedProjects/> - <manifest generateManifest="true" manifestLocation="" manifestVersion="1.0" reuseManifest="false" saveManifest="false" usesManifest="true"> - <sealing sealJar="false"> - <packagesToSeal/> - <packagesToUnSeal/> - </sealing> - </manifest> - <selectedElements exportClassFiles="true" exportJavaFiles="false" exportOutputFolder="false"> - <javaElement handleIdentifier="=layoutlib_create/tests<mock_android.widget"/> - <javaElement handleIdentifier="=layoutlib_create/tests<mock_android.view"/> - <javaElement handleIdentifier="=layoutlib_create/tests<mock_android.dummy"/> - </selectedElements> -</jardesc> diff --git a/tools/layoutlib/create/tests/mock_android/dummy/InnerTest.java b/tools/layoutlib/create/tests/mock_android/dummy/InnerTest.java deleted file mode 100644 index e355ead..0000000 --- a/tools/layoutlib/create/tests/mock_android/dummy/InnerTest.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (C) 2008 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 mock_android.dummy; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Iterator; - -public class InnerTest { - - private int mSomeField; - private MyStaticInnerClass mInnerInstance; - private MyIntEnum mTheIntEnum; - private MyGenerics1<int[][], InnerTest, MyIntEnum, float[]> mGeneric1; - - public class NotStaticInner2 extends NotStaticInner1 { - - } - - public class NotStaticInner1 { - - public void someThing() { - mSomeField = 2; - mInnerInstance = null; - } - - } - - private static class MyStaticInnerClass { - - } - - private static class DerivingClass extends InnerTest { - - } - - // enums are a kind of inner static class - public enum MyIntEnum { - VALUE0(0), - VALUE1(1), - VALUE2(2); - - MyIntEnum(int myInt) { - this.myInt = myInt; - } - final int myInt; - } - - public static class MyGenerics1<T, U, V, W> { - public MyGenerics1() { - int a = 1; - } - } - - public <X> void genericMethod1(X a, X[] a) { - } - - public <X, Y> void genericMethod2(X a, List<Y> b) { - } - - public <X, Y> void genericMethod3(X a, List<Y extends InnerTest> b) { - } - - public <T extends InnerTest> void genericMethod4(T[] a, Collection<T> b, Collection<?> c) { - Iterator<T> i = b.iterator(); - } - - public void someMethod(InnerTest self) { - mSomeField = self.mSomeField; - MyStaticInnerClass m = new MyStaticInnerClass(); - mInnerInstance = m; - mTheIntEnum = null; - mGeneric1 = new MyGenerics1(); - genericMethod(new DerivingClass[0], new ArrayList<DerivingClass>(), new ArrayList<InnerTest>()); - } -} diff --git a/tools/layoutlib/create/tests/mock_android/view/View.java b/tools/layoutlib/create/tests/mock_android/view/View.java deleted file mode 100644 index a80a98d..0000000 --- a/tools/layoutlib/create/tests/mock_android/view/View.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright (C) 2008 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 mock_android.view; - -public class View { - -} diff --git a/tools/layoutlib/create/tests/mock_android/view/ViewGroup.java b/tools/layoutlib/create/tests/mock_android/view/ViewGroup.java deleted file mode 100644 index 466470f..0000000 --- a/tools/layoutlib/create/tests/mock_android/view/ViewGroup.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright (C) 2008 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 mock_android.view; - -public class ViewGroup extends View { - - public class MarginLayoutParams extends LayoutParams { - - } - - public class LayoutParams { - - } - -} diff --git a/tools/layoutlib/create/tests/mock_android/widget/LinearLayout.java b/tools/layoutlib/create/tests/mock_android/widget/LinearLayout.java deleted file mode 100644 index 3870a63..0000000 --- a/tools/layoutlib/create/tests/mock_android/widget/LinearLayout.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2008 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 mock_android.widget; - -import mock_android.view.ViewGroup; - -public class LinearLayout extends ViewGroup { - - public class LayoutParams extends mock_android.view.ViewGroup.LayoutParams { - - } - -} diff --git a/tools/layoutlib/create/tests/mock_android/widget/TableLayout.java b/tools/layoutlib/create/tests/mock_android/widget/TableLayout.java deleted file mode 100644 index e455e7d..0000000 --- a/tools/layoutlib/create/tests/mock_android/widget/TableLayout.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright (C) 2008 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 mock_android.widget; - -import mock_android.view.ViewGroup; - -public class TableLayout extends ViewGroup { - - public class LayoutParams extends MarginLayoutParams { - - } - -} |