186eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta/* 286eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta * Copyright (C) 2014 The Android Open Source Project 386eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta * 486eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta * Licensed under the Apache License, Version 2.0 (the "License"); 586eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta * you may not use this file except in compliance with the License. 686eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta * You may obtain a copy of the License at 786eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta * 886eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta * http://www.apache.org/licenses/LICENSE-2.0 986eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta * 1086eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta * Unless required by applicable law or agreed to in writing, software 1186eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta * distributed under the License is distributed on an "AS IS" BASIS, 1286eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1386eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta * See the License for the specific language governing permissions and 1486eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta * limitations under the License. 1586eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta */ 1686eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta 1786eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Guptapackage com.android.layoutlib.bridge.intensive.setup; 1886eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta 1986eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Guptaimport com.android.SdkConstants; 2086eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Guptaimport com.android.ide.common.rendering.api.ActionBarCallback; 2186eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Guptaimport com.android.ide.common.rendering.api.AdapterBinding; 2286eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Guptaimport com.android.ide.common.rendering.api.ILayoutPullParser; 2337dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Guptaimport com.android.ide.common.rendering.api.LayoutlibCallback; 243dc19883c571a829c36aa603c04a55c91b00dd57Deepanshu Guptaimport com.android.ide.common.rendering.api.ParserFactory; 2586eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Guptaimport com.android.ide.common.rendering.api.ResourceReference; 2686eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Guptaimport com.android.ide.common.rendering.api.ResourceValue; 27ceb1ab1d2a71c6d4e0cccf110a198ff83cb97e5aDeepanshu Guptaimport com.android.ide.common.rendering.api.SessionParams.Key; 2886eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Guptaimport com.android.ide.common.resources.IntArrayWrapper; 29ceb1ab1d2a71c6d4e0cccf110a198ff83cb97e5aDeepanshu Guptaimport com.android.layoutlib.bridge.android.RenderParamsFlags; 30a035dfbf8ddfc8d301dd96088eb50e8c2e63e487Deepanshu Guptaimport com.android.resources.ResourceType; 3186eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Guptaimport com.android.util.Pair; 3286eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Guptaimport com.android.utils.ILogger; 3386eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta 3478af25584633462e4ab8cf9bafe10f43e7cb2d83Deepanshu Guptaimport org.kxml2.io.KXmlParser; 3578af25584633462e4ab8cf9bafe10f43e7cb2d83Deepanshu Guptaimport org.xmlpull.v1.XmlPullParser; 363dc19883c571a829c36aa603c04a55c91b00dd57Deepanshu Guptaimport org.xmlpull.v1.XmlPullParserException; 3778af25584633462e4ab8cf9bafe10f43e7cb2d83Deepanshu Gupta 38476e582d2ffdf25102d4c55f8c242baa3d21d37fDeepanshu Guptaimport android.annotation.NonNull; 39476e582d2ffdf25102d4c55f8c242baa3d21d37fDeepanshu Guptaimport android.annotation.Nullable; 40476e582d2ffdf25102d4c55f8c242baa3d21d37fDeepanshu Gupta 4186eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Guptaimport java.io.File; 4286eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Guptaimport java.lang.reflect.Constructor; 4386eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Guptaimport java.lang.reflect.Field; 4486eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Guptaimport java.lang.reflect.Modifier; 4586eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Guptaimport java.util.Map; 4686eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta 4786eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Guptaimport com.google.android.collect.Maps; 4886eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta 49a035dfbf8ddfc8d301dd96088eb50e8c2e63e487Deepanshu Guptaimport static org.junit.Assert.fail; 50a035dfbf8ddfc8d301dd96088eb50e8c2e63e487Deepanshu Gupta 5186eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta@SuppressWarnings("deprecation") // For Pair 5237dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Guptapublic class LayoutLibTestCallback extends LayoutlibCallback { 5386eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta 5486eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta private static final String PROJECT_CLASSES_LOCATION = "/testApp/MyApplication/build/intermediates/classes/debug/"; 5586eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta private static final String PACKAGE_NAME = "com.android.layoutlib.test.myapplication"; 5686eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta 5786eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta private final Map<Integer, Pair<ResourceType, String>> mProjectResources = Maps.newHashMap(); 5886eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta private final Map<IntArrayWrapper, String> mStyleableValueToNameMap = Maps.newHashMap(); 5986eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta private final Map<ResourceType, Map<String, Integer>> mResources = Maps.newHashMap(); 6086eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta private final ILogger mLog; 6186eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta private final ActionBarCallback mActionBarCallback = new ActionBarCallback(); 6237dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta private final ClassLoader mModuleClassLoader = new ModuleClassLoader(PROJECT_CLASSES_LOCATION); 6386eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta 6486eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta public LayoutLibTestCallback(ILogger logger) { 6586eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta mLog = logger; 6686eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta } 6786eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta 6886eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta public void initResources() throws ClassNotFoundException { 6937dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta Class<?> rClass = mModuleClassLoader.loadClass(PACKAGE_NAME + ".R"); 7086eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta Class<?>[] nestedClasses = rClass.getDeclaredClasses(); 7186eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta for (Class<?> resClass : nestedClasses) { 7286eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta final ResourceType resType = ResourceType.getEnum(resClass.getSimpleName()); 7386eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta 7486eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta if (resType != null) { 7586eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta final Map<String, Integer> resName2Id = Maps.newHashMap(); 7686eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta mResources.put(resType, resName2Id); 7786eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta 7886eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta for (Field field : resClass.getDeclaredFields()) { 7986eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta final int modifiers = field.getModifiers(); 8086eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta if (Modifier.isStatic(modifiers)) { // May not be final in library projects 8186eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta final Class<?> type = field.getType(); 8286eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta try { 8386eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta if (type.isArray() && type.getComponentType() == int.class) { 8486eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta mStyleableValueToNameMap.put( 8586eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta new IntArrayWrapper((int[]) field.get(null)), 8686eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta field.getName()); 8786eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta } else if (type == int.class) { 8886eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta final Integer value = (Integer) field.get(null); 8986eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta mProjectResources.put(value, Pair.of(resType, field.getName())); 9086eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta resName2Id.put(field.getName(), value); 9186eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta } else { 9286eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta mLog.error(null, "Unknown field type in R class: %1$s", type); 9386eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta } 9486eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta } catch (IllegalAccessException ignored) { 9586eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta mLog.error(ignored, "Malformed R class: %1$s", PACKAGE_NAME + ".R"); 9686eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta } 9786eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta } 9886eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta } 9986eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta } 10086eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta } 10186eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta } 10286eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta 10386eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta 10486eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta @Override 10586eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta public Object loadView(String name, Class[] constructorSignature, Object[] constructorArgs) 10686eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta throws Exception { 10737dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta Class<?> viewClass = mModuleClassLoader.loadClass(name); 10886eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta Constructor<?> viewConstructor = viewClass.getConstructor(constructorSignature); 10986eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta viewConstructor.setAccessible(true); 11086eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta return viewConstructor.newInstance(constructorArgs); 11186eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta } 11286eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta 11386eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta @Override 11486eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta public String getNamespace() { 11586eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta return String.format(SdkConstants.NS_CUSTOM_RESOURCES_S, 11686eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta PACKAGE_NAME); 11786eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta } 11886eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta 11986eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta @Override 12086eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta public Pair<ResourceType, String> resolveResourceId(int id) { 12186eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta return mProjectResources.get(id); 12286eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta } 12386eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta 12486eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta @Override 12586eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta public String resolveResourceId(int[] id) { 12686eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta return mStyleableValueToNameMap.get(new IntArrayWrapper(id)); 12786eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta } 12886eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta 12986eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta @Override 13086eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta public Integer getResourceId(ResourceType type, String name) { 13186eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta return mResources.get(type).get(name); 13286eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta } 13386eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta 13486eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta @Override 13586eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta public ILayoutPullParser getParser(String layoutName) { 136a035dfbf8ddfc8d301dd96088eb50e8c2e63e487Deepanshu Gupta fail("This method shouldn't be called by this version of LayoutLib."); 13786eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta return null; 13886eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta } 13986eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta 14086eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta @Override 14186eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta public ILayoutPullParser getParser(ResourceValue layoutResource) { 14286eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta return new LayoutPullParser(new File(layoutResource.getValue())); 14386eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta } 14486eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta 14586eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta @Override 14686eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta public Object getAdapterItemValue(ResourceReference adapterView, Object adapterCookie, 14786eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta ResourceReference itemRef, int fullPosition, int positionPerType, 14886eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta int fullParentPosition, int parentPositionPerType, ResourceReference viewRef, 14986eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta ViewAttribute viewAttribute, Object defaultValue) { 15086eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta return null; 15186eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta } 15286eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta 15386eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta @Override 15486eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta public AdapterBinding getAdapterBinding(ResourceReference adapterViewRef, Object adapterCookie, 15586eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta Object viewObject) { 15686eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta return null; 15786eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta } 15886eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta 15986eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta @Override 16086eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta public ActionBarCallback getActionBarCallback() { 16186eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta return mActionBarCallback; 16286eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta } 16337dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta 16437dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta @Override 16537dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta public boolean supports(int ideFeature) { 16637dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta return false; 16737dbb8b7f3c069196040eed3a03006647db7fa5bDeepanshu Gupta } 16878af25584633462e4ab8cf9bafe10f43e7cb2d83Deepanshu Gupta 16978af25584633462e4ab8cf9bafe10f43e7cb2d83Deepanshu Gupta @NonNull 17078af25584633462e4ab8cf9bafe10f43e7cb2d83Deepanshu Gupta @Override 1713dc19883c571a829c36aa603c04a55c91b00dd57Deepanshu Gupta public ParserFactory getParserFactory() { 1723dc19883c571a829c36aa603c04a55c91b00dd57Deepanshu Gupta return new ParserFactory() { 1733dc19883c571a829c36aa603c04a55c91b00dd57Deepanshu Gupta @NonNull 1743dc19883c571a829c36aa603c04a55c91b00dd57Deepanshu Gupta @Override 1753dc19883c571a829c36aa603c04a55c91b00dd57Deepanshu Gupta public XmlPullParser createParser(@Nullable String debugName) 1763dc19883c571a829c36aa603c04a55c91b00dd57Deepanshu Gupta throws XmlPullParserException { 1773dc19883c571a829c36aa603c04a55c91b00dd57Deepanshu Gupta return new KXmlParser(); 1783dc19883c571a829c36aa603c04a55c91b00dd57Deepanshu Gupta } 1793dc19883c571a829c36aa603c04a55c91b00dd57Deepanshu Gupta }; 18078af25584633462e4ab8cf9bafe10f43e7cb2d83Deepanshu Gupta } 181ceb1ab1d2a71c6d4e0cccf110a198ff83cb97e5aDeepanshu Gupta 182ceb1ab1d2a71c6d4e0cccf110a198ff83cb97e5aDeepanshu Gupta @Override 183ceb1ab1d2a71c6d4e0cccf110a198ff83cb97e5aDeepanshu Gupta public <T> T getFlag(Key<T> key) { 184ceb1ab1d2a71c6d4e0cccf110a198ff83cb97e5aDeepanshu Gupta if (key.equals(RenderParamsFlags.FLAG_KEY_APPLICATION_PACKAGE)) { 185ceb1ab1d2a71c6d4e0cccf110a198ff83cb97e5aDeepanshu Gupta return (T) PACKAGE_NAME; 186ceb1ab1d2a71c6d4e0cccf110a198ff83cb97e5aDeepanshu Gupta } 187ceb1ab1d2a71c6d4e0cccf110a198ff83cb97e5aDeepanshu Gupta return null; 188ceb1ab1d2a71c6d4e0cccf110a198ff83cb97e5aDeepanshu Gupta } 18986eb8b4e29b1ad889fc814bae723d4d6e491f53fDeepanshu Gupta} 190