• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php
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.ide.eclipse.adt.internal.sdk;
18 
19 import com.android.ide.eclipse.adt.AdtPlugin;
20 import com.android.ide.eclipse.adt.internal.editors.descriptors.IDescriptorProvider;
21 import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors;
22 import com.android.ide.eclipse.adt.internal.editors.manifest.descriptors.AndroidManifestDescriptors;
23 import com.android.ide.eclipse.adt.internal.editors.menu.descriptors.MenuDescriptors;
24 import com.android.ide.eclipse.adt.internal.editors.resources.descriptors.ResourcesDescriptors;
25 import com.android.ide.eclipse.adt.internal.editors.xml.descriptors.XmlDescriptors;
26 import com.android.ide.eclipse.adt.internal.resources.IResourceRepository;
27 import com.android.ide.eclipse.adt.internal.resources.manager.ProjectResources;
28 import com.android.layoutlib.api.ILayoutBridge;
29 import com.android.sdklib.IAndroidTarget;
30 import com.android.sdklib.IAndroidTarget.IOptionalLibrary;
31 
32 import java.lang.reflect.Field;
33 import java.util.ArrayList;
34 import java.util.Hashtable;
35 import java.util.Map;
36 
37 /**
38  * This class contains the data of an Android Target as loaded from the SDK.
39  */
40 public class AndroidTargetData {
41 
42     public final static int DESCRIPTOR_MANIFEST = 1;
43     public final static int DESCRIPTOR_LAYOUT = 2;
44     public final static int DESCRIPTOR_MENU = 3;
45     public final static int DESCRIPTOR_XML = 4;
46     public final static int DESCRIPTOR_RESOURCES = 5;
47     public final static int DESCRIPTOR_SEARCHABLE = 6;
48     public final static int DESCRIPTOR_PREFERENCES = 7;
49     public final static int DESCRIPTOR_APPWIDGET_PROVIDER = 8;
50 
51     public final static class LayoutBridge {
52         /** Link to the layout bridge */
53         public ILayoutBridge bridge;
54 
55         public LoadStatus status = LoadStatus.LOADING;
56 
57         public ClassLoader classLoader;
58 
59         public int apiLevel;
60 
61         /**
62          * Post rendering clean-up that must be done here so that it's done even for older
63          * versions of the layoutlib.
64          */
cleanUp()65         public void cleanUp() {
66             try {
67                 Class<?> looperClass = classLoader.loadClass("android.os.Looper"); //$NON-NLS-1$
68                 Field threadLocalField = looperClass.getField("sThreadLocal"); //$NON-NLS-1$
69                 if (threadLocalField != null) {
70                     threadLocalField.setAccessible(true);
71                     // get object. Field is static so no need to pass an object
72                     ThreadLocal<?> threadLocal = (ThreadLocal<?>) threadLocalField.get(null);
73                     if (threadLocal != null) {
74                         threadLocal.remove();
75                     }
76                 }
77             } catch (Exception e) {
78                 AdtPlugin.log(e, "Failed to clean up bridge for API level %d", apiLevel);
79             }
80         }
81     }
82 
83     private final IAndroidTarget mTarget;
84 
85     private DexWrapper mDexWrapper;
86 
87     /**
88      * mAttributeValues is a map { key => list [ values ] }.
89      * The key for the map is "(element-xml-name,attribute-namespace:attribute-xml-local-name)".
90      * The attribute namespace prefix must be:
91      * - "android" for AndroidConstants.NS_RESOURCES
92      * - "xmlns" for the XMLNS URI.
93      *
94      * This is used for attributes that do not have a unique name, but still need to be populated
95      * with values in the UI. Uniquely named attributes have their values in {@link #mEnumValueMap}.
96      */
97     private Hashtable<String, String[]> mAttributeValues = new Hashtable<String, String[]>();
98 
99     private IResourceRepository mSystemResourceRepository;
100 
101     private AndroidManifestDescriptors mManifestDescriptors;
102     private LayoutDescriptors mLayoutDescriptors;
103     private MenuDescriptors mMenuDescriptors;
104     private XmlDescriptors mXmlDescriptors;
105 
106     private Map<String, Map<String, Integer>> mEnumValueMap;
107 
108     private ProjectResources mFrameworkResources;
109     private LayoutBridge mLayoutBridge;
110 
111     private boolean mLayoutBridgeInit = false;
112 
AndroidTargetData(IAndroidTarget androidTarget)113     AndroidTargetData(IAndroidTarget androidTarget) {
114         mTarget = androidTarget;
115     }
116 
setDexWrapper(DexWrapper wrapper)117     void setDexWrapper(DexWrapper wrapper) {
118         mDexWrapper = wrapper;
119     }
120 
121     /**
122      * Creates an AndroidTargetData object.
123      * @param platformLibraries
124      * @param optionalLibraries
125      */
setExtraData(IResourceRepository systemResourceRepository, AndroidManifestDescriptors manifestDescriptors, LayoutDescriptors layoutDescriptors, MenuDescriptors menuDescriptors, XmlDescriptors xmlDescriptors, Map<String, Map<String, Integer>> enumValueMap, String[] permissionValues, String[] activityIntentActionValues, String[] broadcastIntentActionValues, String[] serviceIntentActionValues, String[] intentCategoryValues, String[] platformLibraries, IOptionalLibrary[] optionalLibraries, ProjectResources resources, LayoutBridge layoutBridge)126     void setExtraData(IResourceRepository systemResourceRepository,
127             AndroidManifestDescriptors manifestDescriptors,
128             LayoutDescriptors layoutDescriptors,
129             MenuDescriptors menuDescriptors,
130             XmlDescriptors xmlDescriptors,
131             Map<String, Map<String, Integer>> enumValueMap,
132             String[] permissionValues,
133             String[] activityIntentActionValues,
134             String[] broadcastIntentActionValues,
135             String[] serviceIntentActionValues,
136             String[] intentCategoryValues,
137             String[] platformLibraries,
138             IOptionalLibrary[] optionalLibraries,
139             ProjectResources resources,
140             LayoutBridge layoutBridge) {
141 
142         mSystemResourceRepository = systemResourceRepository;
143         mManifestDescriptors = manifestDescriptors;
144         mLayoutDescriptors = layoutDescriptors;
145         mMenuDescriptors = menuDescriptors;
146         mXmlDescriptors = xmlDescriptors;
147         mEnumValueMap = enumValueMap;
148         mFrameworkResources = resources;
149         mLayoutBridge = layoutBridge;
150 
151         setPermissions(permissionValues);
152         setIntentFilterActionsAndCategories(activityIntentActionValues, broadcastIntentActionValues,
153                 serviceIntentActionValues, intentCategoryValues);
154         setOptionalLibraries(platformLibraries, optionalLibraries);
155     }
156 
getDexWrapper()157     public DexWrapper getDexWrapper() {
158         return mDexWrapper;
159     }
160 
getSystemResources()161     public IResourceRepository getSystemResources() {
162         return mSystemResourceRepository;
163     }
164 
165     /**
166      * Returns an {@link IDescriptorProvider} from a given Id.
167      * The Id can be one of {@link #DESCRIPTOR_MANIFEST}, {@link #DESCRIPTOR_LAYOUT},
168      * {@link #DESCRIPTOR_MENU}, or {@link #DESCRIPTOR_XML}.
169      * All other values will throw an {@link IllegalArgumentException}.
170      */
getDescriptorProvider(int descriptorId)171     public IDescriptorProvider getDescriptorProvider(int descriptorId) {
172         switch (descriptorId) {
173             case DESCRIPTOR_MANIFEST:
174                 return mManifestDescriptors;
175             case DESCRIPTOR_LAYOUT:
176                 return mLayoutDescriptors;
177             case DESCRIPTOR_MENU:
178                 return mMenuDescriptors;
179             case DESCRIPTOR_XML:
180                 return mXmlDescriptors;
181             case DESCRIPTOR_RESOURCES:
182                 // FIXME: since it's hard-coded the Resources Descriptors are not platform dependent.
183                 return ResourcesDescriptors.getInstance();
184             case DESCRIPTOR_PREFERENCES:
185                 return mXmlDescriptors.getPreferencesProvider();
186             case DESCRIPTOR_APPWIDGET_PROVIDER:
187                 return mXmlDescriptors.getAppWidgetProvider();
188             case DESCRIPTOR_SEARCHABLE:
189                 return mXmlDescriptors.getSearchableProvider();
190             default :
191                  throw new IllegalArgumentException();
192         }
193     }
194 
195     /**
196      * Returns the manifest descriptors.
197      */
getManifestDescriptors()198     public AndroidManifestDescriptors getManifestDescriptors() {
199         return mManifestDescriptors;
200     }
201 
202     /**
203      * Returns the layout Descriptors.
204      */
getLayoutDescriptors()205     public LayoutDescriptors getLayoutDescriptors() {
206         return mLayoutDescriptors;
207     }
208 
209     /**
210      * Returns the menu descriptors.
211      */
getMenuDescriptors()212     public MenuDescriptors getMenuDescriptors() {
213         return mMenuDescriptors;
214     }
215 
216     /**
217      * Returns the XML descriptors
218      */
getXmlDescriptors()219     public XmlDescriptors getXmlDescriptors() {
220         return mXmlDescriptors;
221     }
222 
223     /**
224      * Returns this list of possible values for an XML attribute.
225      * <p/>This should only be called for attributes for which possible values depend on the
226      * parent element node.
227      * <p/>For attributes that have the same values no matter the parent node, use
228      * {@link #getEnumValueMap()}.
229      * @param elementName the name of the element containing the attribute.
230      * @param attributeName the name of the attribute
231      * @return an array of String with the possible values, or <code>null</code> if no values were
232      * found.
233      */
getAttributeValues(String elementName, String attributeName)234     public String[] getAttributeValues(String elementName, String attributeName) {
235         String key = String.format("(%1$s,%2$s)", elementName, attributeName); //$NON-NLS-1$
236         return mAttributeValues.get(key);
237     }
238 
239     /**
240      * Returns this list of possible values for an XML attribute.
241      * <p/>This should only be called for attributes for which possible values depend on the
242      * parent and great-grand-parent element node.
243      * <p/>The typical example of this is for the 'name' attribute under
244      * activity/intent-filter/action
245      * <p/>For attributes that have the same values no matter the parent node, use
246      * {@link #getEnumValueMap()}.
247      * @param elementName the name of the element containing the attribute.
248      * @param attributeName the name of the attribute
249      * @param greatGrandParentElementName the great-grand-parent node.
250      * @return an array of String with the possible values, or <code>null</code> if no values were
251      * found.
252      */
getAttributeValues(String elementName, String attributeName, String greatGrandParentElementName)253     public String[] getAttributeValues(String elementName, String attributeName,
254             String greatGrandParentElementName) {
255         if (greatGrandParentElementName != null) {
256             String key = String.format("(%1$s,%2$s,%3$s)", //$NON-NLS-1$
257                     greatGrandParentElementName, elementName, attributeName);
258             String[] values = mAttributeValues.get(key);
259             if (values != null) {
260                 return values;
261             }
262         }
263 
264         return getAttributeValues(elementName, attributeName);
265     }
266 
267     /**
268      * Returns the enum values map.
269      * <p/>The map defines the possible values for XML attributes. The key is the attribute name
270      * and the value is a map of (string, integer) in which the key (string) is the name of
271      * the value, and the Integer is the numerical value in the compiled binary XML files.
272      */
getEnumValueMap()273     public Map<String, Map<String, Integer>> getEnumValueMap() {
274         return mEnumValueMap;
275     }
276 
277     /**
278      * Returns the {@link ProjectResources} containing the Framework Resources.
279      */
getFrameworkResources()280     public ProjectResources getFrameworkResources() {
281         return mFrameworkResources;
282     }
283 
284     /**
285      * Returns a {@link LayoutBridge} object possibly containing a {@link ILayoutBridge} object.
286      * <p/>If {@link LayoutBridge#bridge} is <code>null</code>, {@link LayoutBridge#status} will
287      * contain the reason (either {@link LoadStatus#LOADING} or {@link LoadStatus#FAILED}).
288      * <p/>Valid {@link ILayoutBridge} objects are always initialized before being returned.
289      */
getLayoutBridge()290     public synchronized LayoutBridge getLayoutBridge() {
291         if (mLayoutBridgeInit == false && mLayoutBridge.bridge != null) {
292             mLayoutBridge.bridge.init(mTarget.getPath(IAndroidTarget.FONTS),
293                     getEnumValueMap());
294             mLayoutBridgeInit = true;
295         }
296         return mLayoutBridge;
297     }
298 
299     /**
300      * Sets the permission values
301      * @param permissionValues the list of permissions
302      */
setPermissions(String[] permissionValues)303     private void setPermissions(String[] permissionValues) {
304         setValues("(uses-permission,android:name)", permissionValues);   //$NON-NLS-1$
305         setValues("(application,android:permission)", permissionValues); //$NON-NLS-1$
306         setValues("(activity,android:permission)", permissionValues);    //$NON-NLS-1$
307         setValues("(receiver,android:permission)", permissionValues);    //$NON-NLS-1$
308         setValues("(service,android:permission)", permissionValues);     //$NON-NLS-1$
309         setValues("(provider,android:permission)", permissionValues);    //$NON-NLS-1$
310     }
311 
setIntentFilterActionsAndCategories(String[] activityIntentActions, String[] broadcastIntentActions, String[] serviceIntentActions, String[] intentCategoryValues)312     private void setIntentFilterActionsAndCategories(String[] activityIntentActions,
313             String[] broadcastIntentActions, String[] serviceIntentActions,
314             String[] intentCategoryValues) {
315         setValues("(activity,action,android:name)", activityIntentActions);  //$NON-NLS-1$
316         setValues("(receiver,action,android:name)", broadcastIntentActions); //$NON-NLS-1$
317         setValues("(service,action,android:name)", serviceIntentActions);    //$NON-NLS-1$
318         setValues("(category,android:name)", intentCategoryValues);          //$NON-NLS-1$
319     }
320 
setOptionalLibraries(String[] platformLibraries, IOptionalLibrary[] optionalLibraries)321     private void setOptionalLibraries(String[] platformLibraries,
322             IOptionalLibrary[] optionalLibraries) {
323 
324         ArrayList<String> libs = new ArrayList<String>();
325 
326         if (platformLibraries != null) {
327             for (String name : platformLibraries) {
328                 libs.add(name);
329             }
330         }
331 
332         if (optionalLibraries != null) {
333             for (int i = 0; i < optionalLibraries.length; i++) {
334                 libs.add(optionalLibraries[i].getName());
335             }
336         }
337         setValues("(uses-library,android:name)",  libs.toArray(new String[libs.size()]));
338     }
339 
340     /**
341      * Sets a (name, values) pair in the hash map.
342      * <p/>
343      * If the name is already present in the map, it is first removed.
344      * @param name the name associated with the values.
345      * @param values The values to add.
346      */
setValues(String name, String[] values)347     private void setValues(String name, String[] values) {
348         mAttributeValues.remove(name);
349         mAttributeValues.put(name, values);
350     }
351 }
352