diff options
| author | 2015-12-01 21:44:56 -0800 | |
|---|---|---|
| committer | 2015-12-01 21:49:12 -0800 | |
| commit | cbb1ba7f493116882b79578ec68646366f29cde4 (patch) | |
| tree | 720f70c91d0bd7bb72d58679a61f5781ead7b571 | |
| parent | 9c165d76010d9f79f5cd71978742a335b6b8d1b4 (diff) | |
Add ability to promote fields.
This adds the ability to promote private fields to public ones to
enable layoutlib to access them. This was first added in change
b556decf75b2b084e1aed54ac7fa23a141eedb7f, but reverted in
847b0d3ad22a47e0bca3d8bc8168fea7a0ba2f80. This is essentially a revert
of the change again, but without the SimpleMonthView related stuff.
Also, promote the Choreographer's field as is needed to support
animations.
Change-Id: Iee45a465c7a1cadd362c1841385941e6232e4900
5 files changed, 117 insertions, 17 deletions
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 index f6c2626e4271..8f0ad01c6dc3 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java @@ -77,6 +77,8 @@ public class AsmGenerator { /** Methods to inject. FQCN of class in which method should be injected => runnable that does * the injection. */ private final Map<String, ICreateInfo.InjectMethodRunnable> mInjectedMethodsMap; + /** A map { FQCN => set { field names } } which should be promoted to public visibility */ + private final Map<String, Set<String>> mPromotedFields; /** * Creates a new generator that can generate the output JAR with the stubbed classes. @@ -109,20 +111,8 @@ public class AsmGenerator { // 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); - } + addToMap(createInfo.getDelegateMethods(), mDelegateMethods); + for (String className : createInfo.getDelegateClassNatives()) { className = binaryToInternalClassName(className); Set<String> methods = mDelegateMethods.get(className); @@ -187,10 +177,34 @@ public class AsmGenerator { returnTypes.add(binaryToInternalClassName(className)); } + mPromotedFields = new HashMap<String, Set<String>>(); + addToMap(createInfo.getPromotedFields(), mPromotedFields); + mInjectedMethodsMap = createInfo.getInjectedMethodsMap(); } /** + * For each value in the array, split the value on '#' and add the parts to the map as key + * and value. + */ + private void addToMap(String[] entries, Map<String, Set<String>> map) { + for (String entry : entries) { + int pos = entry.indexOf('#'); + if (pos <= 0 || pos >= entry.length() - 1) { + return; + } + String className = binaryToInternalClassName(entry.substring(0, pos)); + String methodOrFieldName = entry.substring(pos + 1); + Set<String> set = map.get(className); + if (set == null) { + set = new HashSet<String>(); + map.put(className, set); + } + set.add(methodOrFieldName); + } + } + + /** * 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 "." @@ -380,6 +394,10 @@ public class AsmGenerator { } } + Set<String> promoteFields = mPromotedFields.get(className); + if (promoteFields != null && !promoteFields.isEmpty()) { + cv = new PromoteFieldClassAdapter(cv, promoteFields); + } cr.accept(cv, 0); return cw.toByteArray(); } 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 index 7879d9d5417c..ef2addd3d2c3 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java @@ -120,6 +120,11 @@ public final class CreateInfo implements ICreateInfo { } @Override + public String[] getPromotedFields() { + return PROMOTED_FIELDS; + } + + @Override public Map<String, InjectMethodRunnable> getInjectedMethodsMap() { return INJECTED_METHODS; } @@ -291,9 +296,7 @@ public final class CreateInfo implements ICreateInfo { }; private final static String[] PROMOTED_FIELDS = new String[] { - "android.widget.SimpleMonthView#mTitle", - "android.widget.SimpleMonthView#mCalendar", - "android.widget.SimpleMonthView#mDayOfWeekLabelCalendar" + "android.view.Choreographer#mLastFrameTimeNanos" }; /** 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 index 54b1fe628769..6c62423a2a89 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java @@ -78,6 +78,13 @@ public interface ICreateInfo { Set<String> getExcludedClasses(); /** + * Returns a list of fields which should be promoted to public visibility. The array values + * are in the form of the binary FQCN of the class containing the field and the field name + * separated by a '#'. + */ + String[] getPromotedFields(); + + /** * Returns a map from binary FQCN className to {@link InjectMethodRunnable} which will be * called to inject methods into a class. * Can be empty but must not be null. diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/PromoteFieldClassAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/PromoteFieldClassAdapter.java new file mode 100644 index 000000000000..e4b70da2504f --- /dev/null +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/PromoteFieldClassAdapter.java @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2015 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 java.util.Set; + +import static org.objectweb.asm.Opcodes.ACC_PRIVATE; +import static org.objectweb.asm.Opcodes.ACC_PROTECTED; +import static org.objectweb.asm.Opcodes.ACC_PUBLIC; +import static org.objectweb.asm.Opcodes.ASM4; + +/** + * Promotes given fields to public visibility. + */ +public class PromoteFieldClassAdapter extends ClassVisitor { + + private final Set<String> mFieldNames; + private static final int ACC_NOT_PUBLIC = ~(ACC_PRIVATE | ACC_PROTECTED); + + public PromoteFieldClassAdapter(ClassVisitor cv, Set<String> fieldNames) { + super(ASM4, cv); + mFieldNames = fieldNames; + } + + @Override + public FieldVisitor visitField(int access, String name, String desc, String signature, + Object value) { + if (mFieldNames.contains(name)) { + if ((access & ACC_PUBLIC) == 0) { + access = (access & ACC_NOT_PUBLIC) | ACC_PUBLIC; + } + } + return super.visitField(access, name, desc, signature, value); + } +} 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 index 2c21470d6a2f..8a2235b8526c 100644 --- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java +++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java @@ -138,6 +138,11 @@ public class AsmGeneratorTest { } @Override + public String[] getPromotedFields() { + return new String[0]; + } + + @Override public Map<String, InjectMethodRunnable> getInjectedMethodsMap() { return new HashMap<String, InjectMethodRunnable>(0); } @@ -213,6 +218,11 @@ public class AsmGeneratorTest { } @Override + public String[] getPromotedFields() { + return new String[0]; + } + + @Override public Map<String, InjectMethodRunnable> getInjectedMethodsMap() { return new HashMap<String, InjectMethodRunnable>(0); } @@ -296,6 +306,11 @@ public class AsmGeneratorTest { } @Override + public String[] getPromotedFields() { + return new String[0]; + } + + @Override public Map<String, InjectMethodRunnable> getInjectedMethodsMap() { return new HashMap<String, InjectMethodRunnable>(0); } @@ -374,6 +389,11 @@ public class AsmGeneratorTest { } @Override + public String[] getPromotedFields() { + return new String[0]; + } + + @Override public Map<String, InjectMethodRunnable> getInjectedMethodsMap() { HashMap<String, InjectMethodRunnable> map = new HashMap<String, InjectMethodRunnable>(1); |