• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
17 package com.android.layoutlib.bridge.intensive.setup;
18 
19 import com.android.ide.common.rendering.api.ActionBarCallback;
20 import com.android.ide.common.rendering.api.AdapterBinding;
21 import com.android.ide.common.rendering.api.ILayoutPullParser;
22 import com.android.ide.common.rendering.api.LayoutlibCallback;
23 import com.android.ide.common.rendering.api.ResourceReference;
24 import com.android.ide.common.rendering.api.ResourceValue;
25 import com.android.resources.ResourceType;
26 import com.android.utils.ILogger;
27 
28 import org.kxml2.io.KXmlParser;
29 import org.xmlpull.v1.XmlPullParser;
30 import org.xmlpull.v1.XmlPullParserException;
31 
32 import android.annotation.NonNull;
33 import android.annotation.Nullable;
34 
35 import java.io.ByteArrayInputStream;
36 import java.io.ByteArrayOutputStream;
37 import java.io.File;
38 import java.io.FileInputStream;
39 import java.io.FileNotFoundException;
40 import java.io.IOException;
41 import java.lang.reflect.Constructor;
42 import java.lang.reflect.Field;
43 import java.lang.reflect.Modifier;
44 import java.util.HashMap;
45 import java.util.Map;
46 
47 import com.google.common.io.ByteStreams;
48 
49 import static com.android.ide.common.rendering.api.ResourceNamespace.RES_AUTO;
50 
51 public class LayoutlibBridgeClientCallback extends LayoutlibCallback {
52     private final Map<Integer, ResourceReference> mProjectResources = new HashMap<>();
53     private final Map<ResourceReference, Integer> mResources = new HashMap<>();
54     private final ILogger mLog;
55     private final ActionBarCallback mActionBarCallback = new ActionBarCallback();
56     private final ClassLoader mModuleClassLoader;
57     private String mAdaptiveIconMaskPath;
58     private final String mPackageName;
59 
LayoutlibBridgeClientCallback(ILogger logger, ClassLoader classLoader, String packageName)60     public LayoutlibBridgeClientCallback(ILogger logger, ClassLoader classLoader,
61             String packageName) {
62         mLog = logger;
63         mModuleClassLoader = classLoader;
64         mPackageName = packageName;
65     }
66 
initResources()67     public void initResources() throws ClassNotFoundException {
68         Class<?> rClass = mModuleClassLoader.loadClass(mPackageName + ".R");
69         Class<?>[] nestedClasses = rClass.getDeclaredClasses();
70         for (Class<?> resClass : nestedClasses) {
71             final ResourceType resType = ResourceType.fromClassName(resClass.getSimpleName());
72 
73             if (resType != null) {
74                 for (Field field : resClass.getDeclaredFields()) {
75                     final int modifiers = field.getModifiers();
76                     if (Modifier.isStatic(modifiers)) { // May not be final in library projects
77                         final Class<?> type = field.getType();
78                         try {
79                             if (type == int.class) {
80                                 final Integer val = (Integer) field.get(null);
81                                 ResourceReference reference =
82                                         new ResourceReference(RES_AUTO, resType, field.getName());
83                                 mProjectResources.put(val, reference);
84                                 mResources.put(reference, val);
85                             } else if (!(type.isArray() && type.getComponentType() == int.class)) {
86                                 mLog.error(null, "Unknown field type in R class: %1$s", type);
87                             }
88                         } catch (IllegalAccessException e) {
89                             mLog.error(e, "Malformed R class: %1$s", mPackageName + ".R");
90                         }
91                     }
92                 }
93             }
94         }
95     }
96 
97     @Override
loadView(@onNull String name, @NonNull Class[] constructorSignature, Object[] constructorArgs)98     public Object loadView(@NonNull String name, @NonNull Class[] constructorSignature,
99             Object[] constructorArgs)
100             throws Exception {
101         Class<?> viewClass = mModuleClassLoader.loadClass(name);
102         Constructor<?> viewConstructor = viewClass.getConstructor(constructorSignature);
103         viewConstructor.setAccessible(true);
104         return viewConstructor.newInstance(constructorArgs);
105     }
106 
107     @Override
resolveResourceId(int id)108     public ResourceReference resolveResourceId(int id) {
109         return mProjectResources.get(id);
110     }
111 
112     @Override
getOrGenerateResourceId(@onNull ResourceReference resource)113     public int getOrGenerateResourceId(@NonNull ResourceReference resource) {
114         Integer id = mResources.get(resource);
115         return id != null ? id : 0;
116     }
117 
118     @Override
getParser(@onNull ResourceValue layoutResource)119     public ILayoutPullParser getParser(@NonNull ResourceValue layoutResource) {
120         try {
121             return LayoutPullParser.createFromFile(new File(layoutResource.getValue()));
122         } catch (FileNotFoundException e) {
123             return null;
124         }
125     }
126 
127     @Override
getAdapterBinding(Object viewObject, Map<String, String> attributes)128     public AdapterBinding getAdapterBinding(Object viewObject, Map<String, String> attributes) {
129         return null;
130     }
131 
132     @Override
getActionBarCallback()133     public ActionBarCallback getActionBarCallback() {
134         return mActionBarCallback;
135     }
136 
137     @Override
138     @Nullable
createXmlParserForPsiFile(@onNull String fileName)139     public XmlPullParser createXmlParserForPsiFile(@NonNull String fileName) {
140         return createXmlParserForFile(fileName);
141     }
142 
143     @Override
144     @Nullable
createXmlParserForFile(@onNull String fileName)145     public XmlPullParser createXmlParserForFile(@NonNull String fileName) {
146         try (FileInputStream fileStream = new FileInputStream(fileName)) {
147             // Read data fully to memory to be able to close the file stream.
148             ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream();
149             ByteStreams.copy(fileStream, byteOutputStream);
150             KXmlParser parser = new KXmlParser();
151             parser.setInput(new ByteArrayInputStream(byteOutputStream.toByteArray()), null);
152             parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
153             return parser;
154         } catch (IOException | XmlPullParserException e) {
155             return null;
156         }
157     }
158 
159     @Override
160     @NonNull
createXmlParser()161     public XmlPullParser createXmlParser() {
162         return new KXmlParser();
163     }
164 
165     @Override
getApplicationId()166     public String getApplicationId() {
167         return mPackageName;
168     }
169 
170     @Override
getResourcePackage()171     public String getResourcePackage() {
172         return mPackageName;
173     }
174 
175     @Override
findClass(String name)176     public Class<?> findClass(String name) throws ClassNotFoundException {
177         return mModuleClassLoader.loadClass(name);
178     }
179 }
180