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.annotations.NonNull;
20 import com.android.annotations.Nullable;
21 import com.android.ide.common.rendering.LayoutLibrary;
22 import com.android.ide.common.rendering.api.LayoutLog;
23 import com.android.ide.common.resources.ResourceRepository;
24 import com.android.ide.common.resources.platform.AttributeInfo;
25 import com.android.ide.common.sdk.LoadStatus;
26 import com.android.ide.eclipse.adt.AdtPlugin;
27 import com.android.ide.eclipse.adt.internal.editors.animator.AnimDescriptors;
28 import com.android.ide.eclipse.adt.internal.editors.animator.AnimatorDescriptors;
29 import com.android.ide.eclipse.adt.internal.editors.color.ColorDescriptors;
30 import com.android.ide.eclipse.adt.internal.editors.descriptors.IDescriptorProvider;
31 import com.android.ide.eclipse.adt.internal.editors.drawable.DrawableDescriptors;
32 import com.android.ide.eclipse.adt.internal.editors.layout.descriptors.LayoutDescriptors;
33 import com.android.ide.eclipse.adt.internal.editors.manifest.descriptors.AndroidManifestDescriptors;
34 import com.android.ide.eclipse.adt.internal.editors.menu.descriptors.MenuDescriptors;
35 import com.android.ide.eclipse.adt.internal.editors.otherxml.descriptors.OtherXmlDescriptors;
36 import com.android.ide.eclipse.adt.internal.editors.values.descriptors.ValuesDescriptors;
37 import com.android.ide.eclipse.adt.internal.resources.manager.ProjectResources;
38 import com.android.sdklib.IAndroidTarget;
39 import com.android.sdklib.IAndroidTarget.IOptionalLibrary;
40 
41 import org.eclipse.core.runtime.IStatus;
42 
43 import java.io.File;
44 import java.util.ArrayList;
45 import java.util.Hashtable;
46 import java.util.Map;
47 
48 /**
49  * This class contains the data of an Android Target as loaded from the SDK.
50  */
51 public class AndroidTargetData {
52 
53     public final static int DESCRIPTOR_MANIFEST = 1;
54     public final static int DESCRIPTOR_LAYOUT = 2;
55     public final static int DESCRIPTOR_MENU = 3;
56     public final static int DESCRIPTOR_OTHER_XML = 4;
57     public final static int DESCRIPTOR_RESOURCES = 5;
58     public final static int DESCRIPTOR_SEARCHABLE = 6;
59     public final static int DESCRIPTOR_PREFERENCES = 7;
60     public final static int DESCRIPTOR_APPWIDGET_PROVIDER = 8;
61     public final static int DESCRIPTOR_DRAWABLE = 9;
62     public final static int DESCRIPTOR_ANIMATOR = 10;
63     public final static int DESCRIPTOR_ANIM = 11;
64     public final static int DESCRIPTOR_COLOR = 12;
65 
66     private final IAndroidTarget mTarget;
67 
68     /**
69      * mAttributeValues is a map { key => list [ values ] }.
70      * The key for the map is "(element-xml-name,attribute-namespace:attribute-xml-local-name)".
71      * The attribute namespace prefix must be:
72      * - "android" for SdkConstants.NS_RESOURCES
73      * - "xmlns" for the XMLNS URI.
74      *
75      * This is used for attributes that do not have a unique name, but still need to be populated
76      * with values in the UI. Uniquely named attributes have their values in {@link #mEnumValueMap}.
77      */
78     private Hashtable<String, String[]> mAttributeValues = new Hashtable<String, String[]>();
79 
80     private AndroidManifestDescriptors mManifestDescriptors;
81     private DrawableDescriptors mDrawableDescriptors;
82     private AnimatorDescriptors mAnimatorDescriptors;
83     private AnimDescriptors mAnimDescriptors;
84     private ColorDescriptors mColorDescriptors;
85     private LayoutDescriptors mLayoutDescriptors;
86     private MenuDescriptors mMenuDescriptors;
87     private OtherXmlDescriptors mOtherXmlDescriptors;
88 
89     private Map<String, Map<String, Integer>> mEnumValueMap;
90 
91     private ResourceRepository mFrameworkResources;
92     private LayoutLibrary mLayoutLibrary;
93     private Map<String, AttributeInfo> mAttributeMap;
94 
95     private boolean mLayoutBridgeInit = false;
96 
AndroidTargetData(IAndroidTarget androidTarget)97     AndroidTargetData(IAndroidTarget androidTarget) {
98         mTarget = androidTarget;
99     }
100 
101     /**
102      * Sets the associated map from string attribute name to
103      * {@link AttributeInfo}
104      *
105      * @param attributeMap the map
106      */
setAttributeMap(@onNull Map<String, AttributeInfo> attributeMap)107     public void setAttributeMap(@NonNull Map<String, AttributeInfo> attributeMap) {
108         mAttributeMap = attributeMap;
109     }
110 
111     /**
112      * Returns the associated map from string attribute name to
113      * {@link AttributeInfo}
114      *
115      * @return the map
116      */
117     @Nullable
getAttributeMap()118     public Map<String, AttributeInfo> getAttributeMap() {
119         return mAttributeMap;
120     }
121 
122     /**
123      * Creates an AndroidTargetData object.
124      */
setExtraData( AndroidManifestDescriptors manifestDescriptors, LayoutDescriptors layoutDescriptors, MenuDescriptors menuDescriptors, OtherXmlDescriptors otherXmlDescriptors, DrawableDescriptors drawableDescriptors, AnimatorDescriptors animatorDescriptors, AnimDescriptors animDescriptors, ColorDescriptors colorDescriptors, Map<String, Map<String, Integer>> enumValueMap, String[] permissionValues, String[] activityIntentActionValues, String[] broadcastIntentActionValues, String[] serviceIntentActionValues, String[] intentCategoryValues, String[] platformLibraries, IOptionalLibrary[] optionalLibraries, ResourceRepository frameworkResources, LayoutLibrary layoutLibrary)125     void setExtraData(
126             AndroidManifestDescriptors manifestDescriptors,
127             LayoutDescriptors layoutDescriptors,
128             MenuDescriptors menuDescriptors,
129             OtherXmlDescriptors otherXmlDescriptors,
130             DrawableDescriptors drawableDescriptors,
131             AnimatorDescriptors animatorDescriptors,
132             AnimDescriptors animDescriptors,
133             ColorDescriptors colorDescriptors,
134             Map<String, Map<String, Integer>> enumValueMap,
135             String[] permissionValues,
136             String[] activityIntentActionValues,
137             String[] broadcastIntentActionValues,
138             String[] serviceIntentActionValues,
139             String[] intentCategoryValues,
140             String[] platformLibraries,
141             IOptionalLibrary[] optionalLibraries,
142             ResourceRepository frameworkResources,
143             LayoutLibrary layoutLibrary) {
144 
145         mManifestDescriptors = manifestDescriptors;
146         mDrawableDescriptors = drawableDescriptors;
147         mAnimatorDescriptors = animatorDescriptors;
148         mAnimDescriptors = animDescriptors;
149         mColorDescriptors = colorDescriptors;
150         mLayoutDescriptors = layoutDescriptors;
151         mMenuDescriptors = menuDescriptors;
152         mOtherXmlDescriptors = otherXmlDescriptors;
153         mEnumValueMap = enumValueMap;
154         mFrameworkResources = frameworkResources;
155         mLayoutLibrary = layoutLibrary;
156 
157         setPermissions(permissionValues);
158         setIntentFilterActionsAndCategories(activityIntentActionValues, broadcastIntentActionValues,
159                 serviceIntentActionValues, intentCategoryValues);
160         setOptionalLibraries(platformLibraries, optionalLibraries);
161     }
162 
163     /**
164      * Returns an {@link IDescriptorProvider} from a given Id.
165      * The Id can be one of {@link #DESCRIPTOR_MANIFEST}, {@link #DESCRIPTOR_LAYOUT},
166      * {@link #DESCRIPTOR_MENU}, or {@link #DESCRIPTOR_OTHER_XML}.
167      * All other values will throw an {@link IllegalArgumentException}.
168      */
getDescriptorProvider(int descriptorId)169     public IDescriptorProvider getDescriptorProvider(int descriptorId) {
170         switch (descriptorId) {
171             case DESCRIPTOR_MANIFEST:
172                 return mManifestDescriptors;
173             case DESCRIPTOR_LAYOUT:
174                 return mLayoutDescriptors;
175             case DESCRIPTOR_MENU:
176                 return mMenuDescriptors;
177             case DESCRIPTOR_OTHER_XML:
178                 return mOtherXmlDescriptors;
179             case DESCRIPTOR_RESOURCES:
180                 // FIXME: since it's hard-coded the Resources Descriptors are not platform dependent.
181                 return ValuesDescriptors.getInstance();
182             case DESCRIPTOR_PREFERENCES:
183                 return mOtherXmlDescriptors.getPreferencesProvider();
184             case DESCRIPTOR_APPWIDGET_PROVIDER:
185                 return mOtherXmlDescriptors.getAppWidgetProvider();
186             case DESCRIPTOR_SEARCHABLE:
187                 return mOtherXmlDescriptors.getSearchableProvider();
188             case DESCRIPTOR_DRAWABLE:
189                 return mDrawableDescriptors;
190             case DESCRIPTOR_ANIMATOR:
191                 return mAnimatorDescriptors;
192             case DESCRIPTOR_ANIM:
193                 return mAnimDescriptors;
194             case DESCRIPTOR_COLOR:
195                 return mColorDescriptors;
196             default :
197                  throw new IllegalArgumentException();
198         }
199     }
200 
201     /**
202      * Returns the manifest descriptors.
203      */
getManifestDescriptors()204     public AndroidManifestDescriptors getManifestDescriptors() {
205         return mManifestDescriptors;
206     }
207 
208     /**
209      * Returns the drawable descriptors
210      */
getDrawableDescriptors()211     public DrawableDescriptors getDrawableDescriptors() {
212         return mDrawableDescriptors;
213     }
214 
215     /**
216      * Returns the animation descriptors
217      */
getAnimDescriptors()218     public AnimDescriptors getAnimDescriptors() {
219         return mAnimDescriptors;
220     }
221 
222     /**
223      * Returns the color descriptors
224      */
getColorDescriptors()225     public ColorDescriptors getColorDescriptors() {
226         return mColorDescriptors;
227     }
228 
229     /**
230      * Returns the animator descriptors
231      */
getAnimatorDescriptors()232     public AnimatorDescriptors getAnimatorDescriptors() {
233         return mAnimatorDescriptors;
234     }
235 
236     /**
237      * Returns the layout Descriptors.
238      */
getLayoutDescriptors()239     public LayoutDescriptors getLayoutDescriptors() {
240         return mLayoutDescriptors;
241     }
242 
243     /**
244      * Returns the menu descriptors.
245      */
getMenuDescriptors()246     public MenuDescriptors getMenuDescriptors() {
247         return mMenuDescriptors;
248     }
249 
250     /**
251      * Returns the XML descriptors
252      */
getXmlDescriptors()253     public OtherXmlDescriptors getXmlDescriptors() {
254         return mOtherXmlDescriptors;
255     }
256 
257     /**
258      * Returns this list of possible values for an XML attribute.
259      * <p/>This should only be called for attributes for which possible values depend on the
260      * parent element node.
261      * <p/>For attributes that have the same values no matter the parent node, use
262      * {@link #getEnumValueMap()}.
263      * @param elementName the name of the element containing the attribute.
264      * @param attributeName the name of the attribute
265      * @return an array of String with the possible values, or <code>null</code> if no values were
266      * found.
267      */
getAttributeValues(String elementName, String attributeName)268     public String[] getAttributeValues(String elementName, String attributeName) {
269         String key = String.format("(%1$s,%2$s)", elementName, attributeName); //$NON-NLS-1$
270         return mAttributeValues.get(key);
271     }
272 
273     /**
274      * Returns this list of possible values for an XML attribute.
275      * <p/>This should only be called for attributes for which possible values depend on the
276      * parent and great-grand-parent element node.
277      * <p/>The typical example of this is for the 'name' attribute under
278      * activity/intent-filter/action
279      * <p/>For attributes that have the same values no matter the parent node, use
280      * {@link #getEnumValueMap()}.
281      * @param elementName the name of the element containing the attribute.
282      * @param attributeName the name of the attribute
283      * @param greatGrandParentElementName the great-grand-parent node.
284      * @return an array of String with the possible values, or <code>null</code> if no values were
285      * found.
286      */
getAttributeValues(String elementName, String attributeName, String greatGrandParentElementName)287     public String[] getAttributeValues(String elementName, String attributeName,
288             String greatGrandParentElementName) {
289         if (greatGrandParentElementName != null) {
290             String key = String.format("(%1$s,%2$s,%3$s)", //$NON-NLS-1$
291                     greatGrandParentElementName, elementName, attributeName);
292             String[] values = mAttributeValues.get(key);
293             if (values != null) {
294                 return values;
295             }
296         }
297 
298         return getAttributeValues(elementName, attributeName);
299     }
300 
301     /**
302      * Returns the enum values map.
303      * <p/>The map defines the possible values for XML attributes. The key is the attribute name
304      * and the value is a map of (string, integer) in which the key (string) is the name of
305      * the value, and the Integer is the numerical value in the compiled binary XML files.
306      */
getEnumValueMap()307     public Map<String, Map<String, Integer>> getEnumValueMap() {
308         return mEnumValueMap;
309     }
310 
311     /**
312      * Returns the {@link ProjectResources} containing the Framework Resources.
313      */
getFrameworkResources()314     public ResourceRepository getFrameworkResources() {
315         return mFrameworkResources;
316     }
317 
318     /**
319      * Returns a {@link LayoutLibrary} object possibly containing a {@link LayoutBridge} object.
320      * <p/>If {@link LayoutLibrary#getBridge()} is <code>null</code>,
321      * {@link LayoutBridge#getStatus()} will contain the reason (either {@link LoadStatus#LOADING}
322      * or {@link LoadStatus#FAILED}).
323      * <p/>Valid {@link LayoutBridge} objects are always initialized before being returned.
324      */
getLayoutLibrary()325     public synchronized LayoutLibrary getLayoutLibrary() {
326         if (mLayoutBridgeInit == false && mLayoutLibrary.getStatus() == LoadStatus.LOADED) {
327             boolean ok = mLayoutLibrary.init(
328                     mTarget.getProperties(),
329                     new File(mTarget.getPath(IAndroidTarget.FONTS)),
330                     getEnumValueMap(),
331                     new LayoutLog() {
332 
333                         @Override
334                         public void error(String tag, String message, Throwable throwable,
335                                 Object data) {
336                             AdtPlugin.log(throwable, message);
337                         }
338 
339                         @Override
340                         public void error(String tag, String message, Object data) {
341                             AdtPlugin.log(IStatus.ERROR, message);
342                         }
343 
344                         @Override
345                         public void warning(String tag, String message, Object data) {
346                             AdtPlugin.log(IStatus.WARNING, message);
347                         }
348                     });
349             if (!ok) {
350                 AdtPlugin.log(IStatus.ERROR,
351                         "LayoutLibrary initialization failed");
352             }
353             mLayoutBridgeInit = true;
354         }
355 
356         return mLayoutLibrary;
357     }
358 
359     /**
360      * Sets the permission values
361      * @param permissionValues the list of permissions
362      */
setPermissions(String[] permissionValues)363     private void setPermissions(String[] permissionValues) {
364         setValues("(uses-permission,android:name)", permissionValues);   //$NON-NLS-1$
365         setValues("(application,android:permission)", permissionValues); //$NON-NLS-1$
366         setValues("(activity,android:permission)", permissionValues);    //$NON-NLS-1$
367         setValues("(receiver,android:permission)", permissionValues);    //$NON-NLS-1$
368         setValues("(service,android:permission)", permissionValues);     //$NON-NLS-1$
369         setValues("(provider,android:permission)", permissionValues);    //$NON-NLS-1$
370     }
371 
setIntentFilterActionsAndCategories(String[] activityIntentActions, String[] broadcastIntentActions, String[] serviceIntentActions, String[] intentCategoryValues)372     private void setIntentFilterActionsAndCategories(String[] activityIntentActions,
373             String[] broadcastIntentActions, String[] serviceIntentActions,
374             String[] intentCategoryValues) {
375         setValues("(activity,action,android:name)", activityIntentActions);  //$NON-NLS-1$
376         setValues("(receiver,action,android:name)", broadcastIntentActions); //$NON-NLS-1$
377         setValues("(service,action,android:name)", serviceIntentActions);    //$NON-NLS-1$
378         setValues("(category,android:name)", intentCategoryValues);          //$NON-NLS-1$
379     }
380 
setOptionalLibraries(String[] platformLibraries, IOptionalLibrary[] optionalLibraries)381     private void setOptionalLibraries(String[] platformLibraries,
382             IOptionalLibrary[] optionalLibraries) {
383 
384         ArrayList<String> libs = new ArrayList<String>();
385 
386         if (platformLibraries != null) {
387             for (String name : platformLibraries) {
388                 libs.add(name);
389             }
390         }
391 
392         if (optionalLibraries != null) {
393             for (int i = 0; i < optionalLibraries.length; i++) {
394                 libs.add(optionalLibraries[i].getName());
395             }
396         }
397         setValues("(uses-library,android:name)",  libs.toArray(new String[libs.size()]));
398     }
399 
400     /**
401      * Sets a (name, values) pair in the hash map.
402      * <p/>
403      * If the name is already present in the map, it is first removed.
404      * @param name the name associated with the values.
405      * @param values The values to add.
406      */
setValues(String name, String[] values)407     private void setValues(String name, String[] values) {
408         mAttributeValues.remove(name);
409         mAttributeValues.put(name, values);
410     }
411 
dispose()412     public void dispose() {
413         if (mLayoutLibrary != null) {
414             mLayoutLibrary.dispose();
415         }
416     }
417 }
418