LayoutLibTestCallback.java revision 37dbb8b7f3c069196040eed3a03006647db7fa5b
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.ide.common.rendering.api.ActionBarCallback;
21import com.android.ide.common.rendering.api.AdapterBinding;
22import com.android.ide.common.rendering.api.ILayoutPullParser;
23import com.android.ide.common.rendering.api.LayoutlibCallback;
24import com.android.ide.common.rendering.api.ResourceReference;
25import com.android.ide.common.rendering.api.ResourceValue;
26import com.android.resources.ResourceType;
27import com.android.ide.common.resources.IntArrayWrapper;
28import com.android.util.Pair;
29import com.android.utils.ILogger;
30
31import java.io.File;
32import java.lang.reflect.Constructor;
33import java.lang.reflect.Field;
34import java.lang.reflect.Modifier;
35import java.util.Map;
36
37import com.google.android.collect.Maps;
38
39@SuppressWarnings("deprecation") // For Pair
40public class LayoutLibTestCallback extends LayoutlibCallback {
41
42    private static final String PROJECT_CLASSES_LOCATION = "/testApp/MyApplication/build/intermediates/classes/debug/";
43    private static final String PACKAGE_NAME = "com.android.layoutlib.test.myapplication";
44
45    private final Map<Integer, Pair<ResourceType, String>> mProjectResources = Maps.newHashMap();
46    private final Map<IntArrayWrapper, String> mStyleableValueToNameMap = Maps.newHashMap();
47    private final Map<ResourceType, Map<String, Integer>> mResources = Maps.newHashMap();
48    private final ILogger mLog;
49    private final ActionBarCallback mActionBarCallback = new ActionBarCallback();
50    private final ClassLoader mModuleClassLoader = new ModuleClassLoader(PROJECT_CLASSES_LOCATION);
51
52    public LayoutLibTestCallback(ILogger logger) {
53        mLog = logger;
54    }
55
56    public void initResources() throws ClassNotFoundException {
57        Class<?> rClass = mModuleClassLoader.loadClass(PACKAGE_NAME + ".R");
58        Class<?>[] nestedClasses = rClass.getDeclaredClasses();
59        for (Class<?> resClass : nestedClasses) {
60            final ResourceType resType = ResourceType.getEnum(resClass.getSimpleName());
61
62            if (resType != null) {
63                final Map<String, Integer> resName2Id = Maps.newHashMap();
64                mResources.put(resType, resName2Id);
65
66                for (Field field : resClass.getDeclaredFields()) {
67                    final int modifiers = field.getModifiers();
68                    if (Modifier.isStatic(modifiers)) { // May not be final in library projects
69                        final Class<?> type = field.getType();
70                        try {
71                            if (type.isArray() && type.getComponentType() == int.class) {
72                                mStyleableValueToNameMap.put(
73                                        new IntArrayWrapper((int[]) field.get(null)),
74                                        field.getName());
75                            } else if (type == int.class) {
76                                final Integer value = (Integer) field.get(null);
77                                mProjectResources.put(value, Pair.of(resType, field.getName()));
78                                resName2Id.put(field.getName(), value);
79                            } else {
80                                mLog.error(null, "Unknown field type in R class: %1$s", type);
81                            }
82                        } catch (IllegalAccessException ignored) {
83                            mLog.error(ignored, "Malformed R class: %1$s", PACKAGE_NAME + ".R");
84                        }
85                    }
86                }
87            }
88        }
89    }
90
91
92    @Override
93    public Object loadView(String name, Class[] constructorSignature, Object[] constructorArgs)
94            throws Exception {
95        Class<?> viewClass = mModuleClassLoader.loadClass(name);
96        Constructor<?> viewConstructor = viewClass.getConstructor(constructorSignature);
97        viewConstructor.setAccessible(true);
98        return viewConstructor.newInstance(constructorArgs);
99    }
100
101    @Override
102    public String getNamespace() {
103        return String.format(SdkConstants.NS_CUSTOM_RESOURCES_S,
104                PACKAGE_NAME);
105    }
106
107    @Override
108    public Pair<ResourceType, String> resolveResourceId(int id) {
109        return mProjectResources.get(id);
110    }
111
112    @Override
113    public String resolveResourceId(int[] id) {
114        return mStyleableValueToNameMap.get(new IntArrayWrapper(id));
115    }
116
117    @Override
118    public Integer getResourceId(ResourceType type, String name) {
119        return mResources.get(type).get(name);
120    }
121
122    @Override
123    public ILayoutPullParser getParser(String layoutName) {
124        org.junit.Assert.fail("This method shouldn't be called by this version of LayoutLib.");
125        return null;
126    }
127
128    @Override
129    public ILayoutPullParser getParser(ResourceValue layoutResource) {
130        return new LayoutPullParser(new File(layoutResource.getValue()));
131    }
132
133    @Override
134    public Object getAdapterItemValue(ResourceReference adapterView, Object adapterCookie,
135            ResourceReference itemRef, int fullPosition, int positionPerType,
136            int fullParentPosition, int parentPositionPerType, ResourceReference viewRef,
137            ViewAttribute viewAttribute, Object defaultValue) {
138        return null;
139    }
140
141    @Override
142    public AdapterBinding getAdapterBinding(ResourceReference adapterViewRef, Object adapterCookie,
143            Object viewObject) {
144        return null;
145    }
146
147    @Override
148    public ActionBarCallback getActionBarCallback() {
149        return mActionBarCallback;
150    }
151
152    @Override
153    public boolean supports(int ideFeature) {
154        return false;
155    }
156}
157