/** * Ensure that the package, theme and activity maps are initialized and up to date with respect to * the manifest file */ private void sync() { // Since each of the accessors call sync(), allow a bunch of immediate // accessors to all bypass the file stat() below long now = System.currentTimeMillis(); if (now - mLastChecked < 50 && mManifestFile != null) { return; } mLastChecked = now; if (mManifestFile == null) { IFolderWrapper projectFolder = new IFolderWrapper(mProject); mManifestFile = AndroidManifest.getManifest(projectFolder); if (mManifestFile == null) { return; } } // Check to see if our data is up to date long fileModified = mManifestFile.getModificationStamp(); if (fileModified == mLastModified) { // Already have up to date data return; } mLastModified = fileModified; mActivityThemes = new HashMap<String, String>(); mManifestTheme = null; mTargetSdk = 1; // Default when not specified mMinSdk = 1; // Default when not specified mMinSdkName = ""; // Default when not specified mPackage = ""; // $NON-NLS-1$ mApplicationIcon = null; mApplicationLabel = null; Document document = null; try { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); InputSource is = new InputSource(mManifestFile.getContents()); factory.setNamespaceAware(true); factory.setValidating(false); DocumentBuilder builder = factory.newDocumentBuilder(); document = builder.parse(is); Element root = document.getDocumentElement(); mPackage = root.getAttribute(ATTRIBUTE_PACKAGE); NodeList activities = document.getElementsByTagName(NODE_ACTIVITY); for (int i = 0, n = activities.getLength(); i < n; i++) { Element activity = (Element) activities.item(i); String theme = activity.getAttributeNS(NS_RESOURCES, ATTRIBUTE_THEME); if (theme != null && theme.length() > 0) { String name = activity.getAttributeNS(NS_RESOURCES, ATTRIBUTE_NAME); if (name.startsWith(".") // $NON-NLS-1$ && mPackage != null && mPackage.length() > 0) { name = mPackage + name; } mActivityThemes.put(name, theme); } } NodeList applications = root.getElementsByTagName(AndroidManifest.NODE_APPLICATION); if (applications.getLength() > 0) { assert applications.getLength() == 1; Element application = (Element) applications.item(0); if (application.hasAttributeNS(NS_RESOURCES, ATTRIBUTE_ICON)) { mApplicationIcon = application.getAttributeNS(NS_RESOURCES, ATTRIBUTE_ICON); } if (application.hasAttributeNS(NS_RESOURCES, ATTRIBUTE_LABEL)) { mApplicationLabel = application.getAttributeNS(NS_RESOURCES, ATTRIBUTE_LABEL); } String defaultTheme = application.getAttributeNS(NS_RESOURCES, ATTRIBUTE_THEME); if (defaultTheme != null && !defaultTheme.isEmpty()) { // From manifest theme documentation: // "If that attribute is also not set, the default system theme is used." mManifestTheme = defaultTheme; } } // Look up target SDK NodeList usesSdks = root.getElementsByTagName(NODE_USES_SDK); if (usesSdks.getLength() > 0) { Element usesSdk = (Element) usesSdks.item(0); mMinSdk = getApiVersion(usesSdk, ATTRIBUTE_MIN_SDK_VERSION, 1); mTargetSdk = getApiVersion(usesSdk, ATTRIBUTE_TARGET_SDK_VERSION, mMinSdk); } } catch (SAXException e) { AdtPlugin.log(e, "Malformed manifest"); } catch (Exception e) { AdtPlugin.log(e, "Could not read Manifest data"); } }
/** * Reads the public.xml file in data/res/values/ for a given resource folder and builds up a map * of public resources. * * <p>This map is a subset of the full resource map that only contains framework resources that * are public. * * @param logger a logger to report issues to */ public void loadPublicResources(@Nullable ILogger logger) { IAbstractFolder valueFolder = getResFolder().getFolder(SdkConstants.FD_RES_VALUES); if (valueFolder.exists() == false) { return; } IAbstractFile publicXmlFile = valueFolder.getFile("public.xml"); // $NON-NLS-1$ if (publicXmlFile.exists()) { Reader reader = null; try { reader = new BufferedReader(new InputStreamReader(publicXmlFile.getContents(), Charsets.UTF_8)); KXmlParser parser = new KXmlParser(); parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false); parser.setInput(reader); ResourceType lastType = null; String lastTypeName = ""; while (true) { int event = parser.next(); if (event == XmlPullParser.START_TAG) { // As of API 15 there are a number of "java-symbol" entries here if (!parser.getName().equals("public")) { // $NON-NLS-1$ continue; } String name = null; String typeName = null; for (int i = 0, n = parser.getAttributeCount(); i < n; i++) { String attribute = parser.getAttributeName(i); if (attribute.equals("name")) { // $NON-NLS-1$ name = parser.getAttributeValue(i); if (typeName != null) { // Skip id attribute processing break; } } else if (attribute.equals("type")) { // $NON-NLS-1$ typeName = parser.getAttributeValue(i); } } if (name != null && typeName != null) { ResourceType type = null; if (typeName.equals(lastTypeName)) { type = lastType; } else { type = ResourceType.getEnum(typeName); lastType = type; lastTypeName = typeName; } if (type != null) { ResourceItem match = null; Map<String, ResourceItem> map = mResourceMap.get(type); if (map != null) { match = map.get(name); } if (match != null) { List<ResourceItem> publicList = mPublicResourceMap.get(type); if (publicList == null) { // Pick initial size for the list to hold the public // resources. We could just use map.size() here, // but they're usually much bigger; for example, // in one platform version, there are 1500 drawables // and 1200 strings but only 175 and 25 public ones // respectively. int size; switch (type) { case STYLE: size = 500; break; case ATTR: size = 1000; break; case DRAWABLE: size = 200; break; case ID: size = 50; break; case LAYOUT: case COLOR: case STRING: case ANIM: case INTERPOLATOR: size = 30; break; default: size = 10; break; } publicList = new ArrayList<ResourceItem>(size); mPublicResourceMap.put(type, publicList); } publicList.add(match); } else { // log that there's a public resource that doesn't actually // exist? } } else { // log that there was a reference to a typo that doesn't actually // exist? } } } else if (event == XmlPullParser.END_DOCUMENT) { break; } } } catch (Exception e) { if (logger != null) { logger.error(e, "Can't read and parse public attribute list"); } } finally { if (reader != null) { try { reader.close(); } catch (IOException e) { // Nothing to be done here - we don't care if it closed or not. } } } } // put unmodifiable list for all res type in the public resource map // this will simplify access for (ResourceType type : ResourceType.values()) { List<ResourceItem> list = mPublicResourceMap.get(type); if (list == null) { list = Collections.emptyList(); } else { list = Collections.unmodifiableList(list); } // put the new list in the map mPublicResourceMap.put(type, list); } }