198796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta/* 298796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta * Copyright (C) 2014 The Android Open Source Project 398796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta * 498796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta * Licensed under the Apache License, Version 2.0 (the "License"); 598796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta * you may not use this file except in compliance with the License. 698796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta * You may obtain a copy of the License at 798796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta * 898796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta * http://www.apache.org/licenses/LICENSE-2.0 998796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta * 1098796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta * Unless required by applicable law or agreed to in writing, software 1198796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta * distributed under the License is distributed on an "AS IS" BASIS, 1298796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1398796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta * See the License for the specific language governing permissions and 1498796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta * limitations under the License. 1598796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta */ 1698796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta 1798796b464984574c1abe362478c9f47bda62fe7eDeepanshu Guptapackage com.android.layoutlib.bridge.intensive.setup; 1898796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta 1998796b464984574c1abe362478c9f47bda62fe7eDeepanshu Guptaimport com.android.SdkConstants; 2098796b464984574c1abe362478c9f47bda62fe7eDeepanshu Guptaimport com.android.ide.common.rendering.api.ActionBarCallback; 2198796b464984574c1abe362478c9f47bda62fe7eDeepanshu Guptaimport com.android.ide.common.rendering.api.AdapterBinding; 2298796b464984574c1abe362478c9f47bda62fe7eDeepanshu Guptaimport com.android.ide.common.rendering.api.ILayoutPullParser; 23b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Guptaimport com.android.ide.common.rendering.api.LayoutlibCallback; 244455837e72aa018178c5f8dbc080f7077ad1193fDeepanshu Guptaimport com.android.ide.common.rendering.api.ParserFactory; 2598796b464984574c1abe362478c9f47bda62fe7eDeepanshu Guptaimport com.android.ide.common.rendering.api.ResourceReference; 2698796b464984574c1abe362478c9f47bda62fe7eDeepanshu Guptaimport com.android.ide.common.rendering.api.ResourceValue; 27d6b76a32f54da1ba6031f891ff58ccce5d221a41Deepanshu Guptaimport com.android.ide.common.rendering.api.SessionParams.Key; 2898796b464984574c1abe362478c9f47bda62fe7eDeepanshu Guptaimport com.android.ide.common.resources.IntArrayWrapper; 29d6b76a32f54da1ba6031f891ff58ccce5d221a41Deepanshu Guptaimport com.android.layoutlib.bridge.android.RenderParamsFlags; 30ba6a2dc17b4d86982f7e5dfd4e5b3b51f67e116bDeepanshu Guptaimport com.android.resources.ResourceType; 3198796b464984574c1abe362478c9f47bda62fe7eDeepanshu Guptaimport com.android.util.Pair; 3298796b464984574c1abe362478c9f47bda62fe7eDeepanshu Guptaimport com.android.utils.ILogger; 3398796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta 344bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Guptaimport org.kxml2.io.KXmlParser; 354bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Guptaimport org.xmlpull.v1.XmlPullParser; 364455837e72aa018178c5f8dbc080f7077ad1193fDeepanshu Guptaimport org.xmlpull.v1.XmlPullParserException; 374bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Gupta 38442aee6bc1abfb143dcfa1ba60d696e576d066c4Deepanshu Guptaimport android.annotation.NonNull; 39442aee6bc1abfb143dcfa1ba60d696e576d066c4Deepanshu Guptaimport android.annotation.Nullable; 40442aee6bc1abfb143dcfa1ba60d696e576d066c4Deepanshu Gupta 4198796b464984574c1abe362478c9f47bda62fe7eDeepanshu Guptaimport java.io.File; 42d4c426d085994b714f394b982451cc7fa27ff1b7Diego Perezimport java.io.FileNotFoundException; 4398796b464984574c1abe362478c9f47bda62fe7eDeepanshu Guptaimport java.lang.reflect.Constructor; 4498796b464984574c1abe362478c9f47bda62fe7eDeepanshu Guptaimport java.lang.reflect.Field; 4598796b464984574c1abe362478c9f47bda62fe7eDeepanshu Guptaimport java.lang.reflect.Modifier; 4698796b464984574c1abe362478c9f47bda62fe7eDeepanshu Guptaimport java.util.Map; 4798796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta 4898796b464984574c1abe362478c9f47bda62fe7eDeepanshu Guptaimport com.google.android.collect.Maps; 4998796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta 50ba6a2dc17b4d86982f7e5dfd4e5b3b51f67e116bDeepanshu Guptaimport static org.junit.Assert.fail; 51ba6a2dc17b4d86982f7e5dfd4e5b3b51f67e116bDeepanshu Gupta 5298796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta@SuppressWarnings("deprecation") // For Pair 53b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Guptapublic class LayoutLibTestCallback extends LayoutlibCallback { 5498796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta 5598796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta private static final String PROJECT_CLASSES_LOCATION = "/testApp/MyApplication/build/intermediates/classes/debug/"; 5698796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta private static final String PACKAGE_NAME = "com.android.layoutlib.test.myapplication"; 5798796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta 5898796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta private final Map<Integer, Pair<ResourceType, String>> mProjectResources = Maps.newHashMap(); 5998796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta private final Map<IntArrayWrapper, String> mStyleableValueToNameMap = Maps.newHashMap(); 6098796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta private final Map<ResourceType, Map<String, Integer>> mResources = Maps.newHashMap(); 6198796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta private final ILogger mLog; 6298796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta private final ActionBarCallback mActionBarCallback = new ActionBarCallback(); 63c702b276058dc81072b9db892d7ac9dd35da1935Diego Perez private final ClassLoader mModuleClassLoader; 64b1bd12381b7b0b57eff6d9bb1a5ae23309ab2b5cJerome Gaillard private String mAdaptiveIconMaskPath; 6598796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta 66c702b276058dc81072b9db892d7ac9dd35da1935Diego Perez public LayoutLibTestCallback(ILogger logger, ClassLoader classLoader) { 6798796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta mLog = logger; 68c702b276058dc81072b9db892d7ac9dd35da1935Diego Perez mModuleClassLoader = classLoader; 6998796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta } 7098796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta 7198796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta public void initResources() throws ClassNotFoundException { 72b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta Class<?> rClass = mModuleClassLoader.loadClass(PACKAGE_NAME + ".R"); 7398796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta Class<?>[] nestedClasses = rClass.getDeclaredClasses(); 7498796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta for (Class<?> resClass : nestedClasses) { 7598796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta final ResourceType resType = ResourceType.getEnum(resClass.getSimpleName()); 7698796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta 7798796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta if (resType != null) { 7898796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta final Map<String, Integer> resName2Id = Maps.newHashMap(); 7998796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta mResources.put(resType, resName2Id); 8098796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta 8198796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta for (Field field : resClass.getDeclaredFields()) { 8298796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta final int modifiers = field.getModifiers(); 8398796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta if (Modifier.isStatic(modifiers)) { // May not be final in library projects 8498796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta final Class<?> type = field.getType(); 8598796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta try { 8698796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta if (type.isArray() && type.getComponentType() == int.class) { 8798796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta mStyleableValueToNameMap.put( 8898796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta new IntArrayWrapper((int[]) field.get(null)), 8998796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta field.getName()); 9098796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta } else if (type == int.class) { 9198796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta final Integer value = (Integer) field.get(null); 9298796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta mProjectResources.put(value, Pair.of(resType, field.getName())); 9398796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta resName2Id.put(field.getName(), value); 9498796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta } else { 9598796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta mLog.error(null, "Unknown field type in R class: %1$s", type); 9698796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta } 9798796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta } catch (IllegalAccessException ignored) { 9898796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta mLog.error(ignored, "Malformed R class: %1$s", PACKAGE_NAME + ".R"); 9998796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta } 10098796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta } 10198796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta } 10298796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta } 10398796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta } 10498796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta } 10598796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta 10698796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta 10798796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta @Override 10898796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta public Object loadView(String name, Class[] constructorSignature, Object[] constructorArgs) 10998796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta throws Exception { 110b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta Class<?> viewClass = mModuleClassLoader.loadClass(name); 11198796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta Constructor<?> viewConstructor = viewClass.getConstructor(constructorSignature); 11298796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta viewConstructor.setAccessible(true); 11398796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta return viewConstructor.newInstance(constructorArgs); 11498796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta } 11598796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta 11698796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta @Override 11798796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta public String getNamespace() { 11898796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta return String.format(SdkConstants.NS_CUSTOM_RESOURCES_S, 11998796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta PACKAGE_NAME); 12098796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta } 12198796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta 12298796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta @Override 12398796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta public Pair<ResourceType, String> resolveResourceId(int id) { 12498796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta return mProjectResources.get(id); 12598796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta } 12698796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta 12798796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta @Override 12898796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta public String resolveResourceId(int[] id) { 12998796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta return mStyleableValueToNameMap.get(new IntArrayWrapper(id)); 13098796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta } 13198796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta 13298796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta @Override 13398796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta public Integer getResourceId(ResourceType type, String name) { 1348c9f093a47bb9fe3b483ff47f55d957c51c7a1d9Jerome Gaillard Map<String, Integer> resName2Id = mResources.get(type); 1358c9f093a47bb9fe3b483ff47f55d957c51c7a1d9Jerome Gaillard if (resName2Id == null) { 1368c9f093a47bb9fe3b483ff47f55d957c51c7a1d9Jerome Gaillard return null; 1378c9f093a47bb9fe3b483ff47f55d957c51c7a1d9Jerome Gaillard } 1388c9f093a47bb9fe3b483ff47f55d957c51c7a1d9Jerome Gaillard return resName2Id.get(name); 13998796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta } 14098796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta 14198796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta @Override 14298796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta public ILayoutPullParser getParser(String layoutName) { 143ba6a2dc17b4d86982f7e5dfd4e5b3b51f67e116bDeepanshu Gupta fail("This method shouldn't be called by this version of LayoutLib."); 14498796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta return null; 14598796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta } 14698796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta 14798796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta @Override 14898796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta public ILayoutPullParser getParser(ResourceValue layoutResource) { 149d4c426d085994b714f394b982451cc7fa27ff1b7Diego Perez try { 150d4c426d085994b714f394b982451cc7fa27ff1b7Diego Perez return LayoutPullParser.createFromFile(new File(layoutResource.getValue())); 151d4c426d085994b714f394b982451cc7fa27ff1b7Diego Perez } catch (FileNotFoundException e) { 152d4c426d085994b714f394b982451cc7fa27ff1b7Diego Perez return null; 153d4c426d085994b714f394b982451cc7fa27ff1b7Diego Perez } 15498796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta } 15598796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta 15698796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta @Override 15798796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta public Object getAdapterItemValue(ResourceReference adapterView, Object adapterCookie, 15898796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta ResourceReference itemRef, int fullPosition, int positionPerType, 15998796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta int fullParentPosition, int parentPositionPerType, ResourceReference viewRef, 16098796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta ViewAttribute viewAttribute, Object defaultValue) { 16198796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta return null; 16298796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta } 16398796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta 16498796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta @Override 16598796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta public AdapterBinding getAdapterBinding(ResourceReference adapterViewRef, Object adapterCookie, 16698796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta Object viewObject) { 16798796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta return null; 16898796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta } 16998796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta 17098796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta @Override 17198796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta public ActionBarCallback getActionBarCallback() { 17298796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta return mActionBarCallback; 17398796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta } 174b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta 175b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta @Override 176b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta public boolean supports(int ideFeature) { 177b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta return false; 178b111e84752652ec862efa7e0fcaa224430feb97fDeepanshu Gupta } 1794bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Gupta 1804bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Gupta @NonNull 1814bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Gupta @Override 1824455837e72aa018178c5f8dbc080f7077ad1193fDeepanshu Gupta public ParserFactory getParserFactory() { 1834455837e72aa018178c5f8dbc080f7077ad1193fDeepanshu Gupta return new ParserFactory() { 1844455837e72aa018178c5f8dbc080f7077ad1193fDeepanshu Gupta @NonNull 1854455837e72aa018178c5f8dbc080f7077ad1193fDeepanshu Gupta @Override 1864455837e72aa018178c5f8dbc080f7077ad1193fDeepanshu Gupta public XmlPullParser createParser(@Nullable String debugName) 1874455837e72aa018178c5f8dbc080f7077ad1193fDeepanshu Gupta throws XmlPullParserException { 1884455837e72aa018178c5f8dbc080f7077ad1193fDeepanshu Gupta return new KXmlParser(); 1894455837e72aa018178c5f8dbc080f7077ad1193fDeepanshu Gupta } 1904455837e72aa018178c5f8dbc080f7077ad1193fDeepanshu Gupta }; 1914bf28b6af45f76a33b466ad8157aa1844716cbcbDeepanshu Gupta } 192d6b76a32f54da1ba6031f891ff58ccce5d221a41Deepanshu Gupta 193d6b76a32f54da1ba6031f891ff58ccce5d221a41Deepanshu Gupta @Override 194d6b76a32f54da1ba6031f891ff58ccce5d221a41Deepanshu Gupta public <T> T getFlag(Key<T> key) { 195d6b76a32f54da1ba6031f891ff58ccce5d221a41Deepanshu Gupta if (key.equals(RenderParamsFlags.FLAG_KEY_APPLICATION_PACKAGE)) { 196d6b76a32f54da1ba6031f891ff58ccce5d221a41Deepanshu Gupta return (T) PACKAGE_NAME; 197d6b76a32f54da1ba6031f891ff58ccce5d221a41Deepanshu Gupta } 198b1bd12381b7b0b57eff6d9bb1a5ae23309ab2b5cJerome Gaillard if (key.equals(RenderParamsFlags.FLAG_KEY_ADAPTIVE_ICON_MASK_PATH)) { 199b1bd12381b7b0b57eff6d9bb1a5ae23309ab2b5cJerome Gaillard return (T) mAdaptiveIconMaskPath; 200b1bd12381b7b0b57eff6d9bb1a5ae23309ab2b5cJerome Gaillard } 201d6b76a32f54da1ba6031f891ff58ccce5d221a41Deepanshu Gupta return null; 202d6b76a32f54da1ba6031f891ff58ccce5d221a41Deepanshu Gupta } 203b1bd12381b7b0b57eff6d9bb1a5ae23309ab2b5cJerome Gaillard 204b1bd12381b7b0b57eff6d9bb1a5ae23309ab2b5cJerome Gaillard public void setAdaptiveIconMaskPath(String adaptiveIconMaskPath) { 205b1bd12381b7b0b57eff6d9bb1a5ae23309ab2b5cJerome Gaillard mAdaptiveIconMaskPath = adaptiveIconMaskPath; 206b1bd12381b7b0b57eff6d9bb1a5ae23309ab2b5cJerome Gaillard } 20798796b464984574c1abe362478c9f47bda62fe7eDeepanshu Gupta} 208