LayoutLibTestCallback.java revision 78af25584633462e4ab8cf9bafe10f43e7cb2d83
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.layoutlib.bridge.intensive.setup; 18 19import com.android.SdkConstants; 20import com.android.annotations.NonNull; 21import com.android.annotations.Nullable; 22import com.android.ide.common.rendering.api.ActionBarCallback; 23import com.android.ide.common.rendering.api.AdapterBinding; 24import com.android.ide.common.rendering.api.ILayoutPullParser; 25import com.android.ide.common.rendering.api.LayoutlibCallback; 26import com.android.ide.common.rendering.api.ResourceReference; 27import com.android.ide.common.rendering.api.ResourceValue; 28import com.android.ide.common.resources.IntArrayWrapper; 29import com.android.resources.ResourceType; 30import com.android.util.Pair; 31import com.android.utils.ILogger; 32 33import org.kxml2.io.KXmlParser; 34import org.xmlpull.v1.XmlPullParser; 35 36import java.io.File; 37import java.lang.reflect.Constructor; 38import java.lang.reflect.Field; 39import java.lang.reflect.Modifier; 40import java.util.Map; 41 42import com.google.android.collect.Maps; 43 44import static org.junit.Assert.fail; 45 46@SuppressWarnings("deprecation") // For Pair 47public class LayoutLibTestCallback extends LayoutlibCallback { 48 49 private static final String PROJECT_CLASSES_LOCATION = "/testApp/MyApplication/build/intermediates/classes/debug/"; 50 private static final String PACKAGE_NAME = "com.android.layoutlib.test.myapplication"; 51 52 private final Map<Integer, Pair<ResourceType, String>> mProjectResources = Maps.newHashMap(); 53 private final Map<IntArrayWrapper, String> mStyleableValueToNameMap = Maps.newHashMap(); 54 private final Map<ResourceType, Map<String, Integer>> mResources = Maps.newHashMap(); 55 private final ILogger mLog; 56 private final ActionBarCallback mActionBarCallback = new ActionBarCallback(); 57 private final ClassLoader mModuleClassLoader = new ModuleClassLoader(PROJECT_CLASSES_LOCATION); 58 59 public LayoutLibTestCallback(ILogger logger) { 60 mLog = logger; 61 } 62 63 public void initResources() throws ClassNotFoundException { 64 Class<?> rClass = mModuleClassLoader.loadClass(PACKAGE_NAME + ".R"); 65 Class<?>[] nestedClasses = rClass.getDeclaredClasses(); 66 for (Class<?> resClass : nestedClasses) { 67 final ResourceType resType = ResourceType.getEnum(resClass.getSimpleName()); 68 69 if (resType != null) { 70 final Map<String, Integer> resName2Id = Maps.newHashMap(); 71 mResources.put(resType, resName2Id); 72 73 for (Field field : resClass.getDeclaredFields()) { 74 final int modifiers = field.getModifiers(); 75 if (Modifier.isStatic(modifiers)) { // May not be final in library projects 76 final Class<?> type = field.getType(); 77 try { 78 if (type.isArray() && type.getComponentType() == int.class) { 79 mStyleableValueToNameMap.put( 80 new IntArrayWrapper((int[]) field.get(null)), 81 field.getName()); 82 } else if (type == int.class) { 83 final Integer value = (Integer) field.get(null); 84 mProjectResources.put(value, Pair.of(resType, field.getName())); 85 resName2Id.put(field.getName(), value); 86 } else { 87 mLog.error(null, "Unknown field type in R class: %1$s", type); 88 } 89 } catch (IllegalAccessException ignored) { 90 mLog.error(ignored, "Malformed R class: %1$s", PACKAGE_NAME + ".R"); 91 } 92 } 93 } 94 } 95 } 96 } 97 98 99 @Override 100 public Object loadView(String name, Class[] constructorSignature, Object[] constructorArgs) 101 throws Exception { 102 Class<?> viewClass = mModuleClassLoader.loadClass(name); 103 Constructor<?> viewConstructor = viewClass.getConstructor(constructorSignature); 104 viewConstructor.setAccessible(true); 105 return viewConstructor.newInstance(constructorArgs); 106 } 107 108 @Override 109 public String getNamespace() { 110 return String.format(SdkConstants.NS_CUSTOM_RESOURCES_S, 111 PACKAGE_NAME); 112 } 113 114 @Override 115 public Pair<ResourceType, String> resolveResourceId(int id) { 116 return mProjectResources.get(id); 117 } 118 119 @Override 120 public String resolveResourceId(int[] id) { 121 return mStyleableValueToNameMap.get(new IntArrayWrapper(id)); 122 } 123 124 @Override 125 public Integer getResourceId(ResourceType type, String name) { 126 return mResources.get(type).get(name); 127 } 128 129 @Override 130 public ILayoutPullParser getParser(String layoutName) { 131 fail("This method shouldn't be called by this version of LayoutLib."); 132 return null; 133 } 134 135 @Override 136 public ILayoutPullParser getParser(ResourceValue layoutResource) { 137 return new LayoutPullParser(new File(layoutResource.getValue())); 138 } 139 140 @Override 141 public Object getAdapterItemValue(ResourceReference adapterView, Object adapterCookie, 142 ResourceReference itemRef, int fullPosition, int positionPerType, 143 int fullParentPosition, int parentPositionPerType, ResourceReference viewRef, 144 ViewAttribute viewAttribute, Object defaultValue) { 145 return null; 146 } 147 148 @Override 149 public AdapterBinding getAdapterBinding(ResourceReference adapterViewRef, Object adapterCookie, 150 Object viewObject) { 151 return null; 152 } 153 154 @Override 155 public ActionBarCallback getActionBarCallback() { 156 return mActionBarCallback; 157 } 158 159 @Override 160 public boolean supports(int ideFeature) { 161 return false; 162 } 163 164 @NonNull 165 @Override 166 public XmlPullParser createParser(@Nullable String name) { 167 return new KXmlParser(); 168 } 169} 170