Loading tools/layoutlib/create/README.txt +29 −5 Original line number Diff line number Diff line Loading @@ -30,9 +30,9 @@ The Android JAR can't be used directly in Eclipse: Consequently this tool: - parses the input JAR, - modifies some of the classes directly using some bytecode manipulation, - filters some packages and removes some that we don't want to end in the output JAR, - filters some packages and removes those we don't want in the output JAR, - injects some new classes, - and generates a modified JAR file that is suitable for the Android plugin - 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. Loading Loading @@ -63,7 +63,7 @@ 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 the view needs to be kept. 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 Loading @@ -90,6 +90,7 @@ 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. Loading @@ -114,6 +115,9 @@ 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. Loading @@ -131,8 +135,7 @@ 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. An extension being worked on is to actually replace these listeners by direct calls to a delegate class, complete with parameters. This strategy is now obsolete and replaced by the method delegates. - Strategies Loading Loading @@ -160,6 +163,9 @@ 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 Loading Loading @@ -195,6 +201,24 @@ example, the inner class Paint$Style in the Paint class should be discarded and 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 - -------------- Loading tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java +3 −0 Original line number Diff line number Diff line Loading @@ -51,6 +51,8 @@ public final class CreateInfo implements ICreateInfo { * 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. */ public String[] getOverriddenMethods() { return OVERRIDDEN_METHODS; Loading Loading @@ -153,6 +155,7 @@ public final class CreateInfo implements ICreateInfo { /** * 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[] { }; Loading tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java +50 −12 Original line number Diff line number Diff line Loading @@ -31,6 +31,11 @@ import java.util.Set; */ public class DelegateClassAdapter extends ClassAdapter { /** 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; Loading Loading @@ -73,22 +78,55 @@ public class DelegateClassAdapter extends ClassAdapter { boolean useDelegate = (isNative && mDelegateMethods.contains(ALL_NATIVES)) || mDelegateMethods.contains(name); if (useDelegate) { // remove native access = access & ~Opcodes.ACC_NATIVE; 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); } MethodVisitor mw = super.visitMethod(access, name, desc, signature, exceptions); if (useDelegate) { DelegateMethodAdapter a = new DelegateMethodAdapter(mLog, mw, mClassName, name, desc, isStatic); 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.generateCode(); } else { return a; } a.generateDelegateCode(); return mwDelegate; } return mw; // 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 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; } } tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java→tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter2.java +164 −91 File changed and moved.Preview size limit exceeded, changes collapsed. Show changes tools/layoutlib/create/src/com/android/tools/layoutlib/create/StubMethodAdapter.java +7 −6 Original line number Diff line number Diff line Loading @@ -250,6 +250,7 @@ class StubMethodAdapter implements MethodVisitor { generatePop(); generateInvoke(); mMessageGenerated = true; //$FALL-THROUGH$ default: mParentVisitor.visitInsn(opcode); } Loading Loading
tools/layoutlib/create/README.txt +29 −5 Original line number Diff line number Diff line Loading @@ -30,9 +30,9 @@ The Android JAR can't be used directly in Eclipse: Consequently this tool: - parses the input JAR, - modifies some of the classes directly using some bytecode manipulation, - filters some packages and removes some that we don't want to end in the output JAR, - filters some packages and removes those we don't want in the output JAR, - injects some new classes, - and generates a modified JAR file that is suitable for the Android plugin - 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. Loading Loading @@ -63,7 +63,7 @@ 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 the view needs to be kept. 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 Loading @@ -90,6 +90,7 @@ 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. Loading @@ -114,6 +115,9 @@ 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. Loading @@ -131,8 +135,7 @@ 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. An extension being worked on is to actually replace these listeners by direct calls to a delegate class, complete with parameters. This strategy is now obsolete and replaced by the method delegates. - Strategies Loading Loading @@ -160,6 +163,9 @@ 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 Loading Loading @@ -195,6 +201,24 @@ example, the inner class Paint$Style in the Paint class should be discarded and 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 - -------------- Loading
tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java +3 −0 Original line number Diff line number Diff line Loading @@ -51,6 +51,8 @@ public final class CreateInfo implements ICreateInfo { * 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. */ public String[] getOverriddenMethods() { return OVERRIDDEN_METHODS; Loading Loading @@ -153,6 +155,7 @@ public final class CreateInfo implements ICreateInfo { /** * 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[] { }; Loading
tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java +50 −12 Original line number Diff line number Diff line Loading @@ -31,6 +31,11 @@ import java.util.Set; */ public class DelegateClassAdapter extends ClassAdapter { /** 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; Loading Loading @@ -73,22 +78,55 @@ public class DelegateClassAdapter extends ClassAdapter { boolean useDelegate = (isNative && mDelegateMethods.contains(ALL_NATIVES)) || mDelegateMethods.contains(name); if (useDelegate) { // remove native access = access & ~Opcodes.ACC_NATIVE; 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); } MethodVisitor mw = super.visitMethod(access, name, desc, signature, exceptions); if (useDelegate) { DelegateMethodAdapter a = new DelegateMethodAdapter(mLog, mw, mClassName, name, desc, isStatic); 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.generateCode(); } else { return a; } a.generateDelegateCode(); return mwDelegate; } return mw; // 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 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; } }
tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java→tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter2.java +164 −91 File changed and moved.Preview size limit exceeded, changes collapsed. Show changes
tools/layoutlib/create/src/com/android/tools/layoutlib/create/StubMethodAdapter.java +7 −6 Original line number Diff line number Diff line Loading @@ -250,6 +250,7 @@ class StubMethodAdapter implements MethodVisitor { generatePop(); generateInvoke(); mMessageGenerated = true; //$FALL-THROUGH$ default: mParentVisitor.visitInsn(opcode); } Loading