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 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 */ 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 118 public Map<String, AttributeInfo> getAttributeMap() { 119 return mAttributeMap; 120 } 121 122 /** 123 * Creates an AndroidTargetData object. 124 */ 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 */ 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 */ 204 public AndroidManifestDescriptors getManifestDescriptors() { 205 return mManifestDescriptors; 206 } 207 208 /** 209 * Returns the drawable descriptors 210 */ 211 public DrawableDescriptors getDrawableDescriptors() { 212 return mDrawableDescriptors; 213 } 214 215 /** 216 * Returns the animation descriptors 217 */ 218 public AnimDescriptors getAnimDescriptors() { 219 return mAnimDescriptors; 220 } 221 222 /** 223 * Returns the color descriptors 224 */ 225 public ColorDescriptors getColorDescriptors() { 226 return mColorDescriptors; 227 } 228 229 /** 230 * Returns the animator descriptors 231 */ 232 public AnimatorDescriptors getAnimatorDescriptors() { 233 return mAnimatorDescriptors; 234 } 235 236 /** 237 * Returns the layout Descriptors. 238 */ 239 public LayoutDescriptors getLayoutDescriptors() { 240 return mLayoutDescriptors; 241 } 242 243 /** 244 * Returns the menu descriptors. 245 */ 246 public MenuDescriptors getMenuDescriptors() { 247 return mMenuDescriptors; 248 } 249 250 /** 251 * Returns the XML descriptors 252 */ 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 */ 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 */ 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 */ 307 public Map<String, Map<String, Integer>> getEnumValueMap() { 308 return mEnumValueMap; 309 } 310 311 /** 312 * Returns the {@link ProjectResources} containing the Framework Resources. 313 */ 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 */ 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 */ 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 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 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 */ 407 private void setValues(String name, String[] values) { 408 mAttributeValues.remove(name); 409 mAttributeValues.put(name, values); 410 } 411 412 public void dispose() { 413 if (mLayoutLibrary != null) { 414 mLayoutLibrary.dispose(); 415 } 416 } 417 } 418