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