/** * Ensures that the repository has been initialized again after a call to {@link * ResourceRepository#clear()} * * @return true if the repository was just re-initialized. */ public synchronized boolean ensureInitialized() { if (mCleared && !mInitializing) { ScanningContext context = new ScanningContext(this); mInitializing = true; IAbstractResource[] resources = mResourceFolder.listMembers(); for (IAbstractResource res : resources) { if (res instanceof IAbstractFolder) { IAbstractFolder folder = (IAbstractFolder) res; ResourceFolder resFolder = processFolder(folder); if (resFolder != null) { // now we process the content of the folder IAbstractResource[] files = folder.listMembers(); for (IAbstractResource fileRes : files) { if (fileRes instanceof IAbstractFile) { IAbstractFile file = (IAbstractFile) fileRes; resFolder.processFile(file, ResourceDeltaKind.ADDED, context); } } } } } mInitializing = false; mCleared = false; return true; } return false; }
/** * Removes a {@link ResourceFolder} associated with the specified {@link IAbstractFolder}. * * @param type The type of the folder * @param removedFolder the IAbstractFolder object. * @param context the scanning context * @return the {@link ResourceFolder} that was removed, or null if no matches were found. */ @Nullable public ResourceFolder removeFolder( @NonNull ResourceFolderType type, @NonNull IAbstractFolder removedFolder, @Nullable ScanningContext context) { ensureInitialized(); // get the list of folders for the resource type. List<ResourceFolder> list = mFolderMap.get(type); if (list != null) { int count = list.size(); for (int i = 0; i < count; i++) { ResourceFolder resFolder = list.get(i); IAbstractFolder folder = resFolder.getFolder(); if (removedFolder.equals(folder)) { // we found the matching ResourceFolder. we need to remove it. list.remove(i); // remove its content resFolder.dispose(context); return resFolder; } } } return null; }
/** * Returns the {@link ResourceFolder} associated with a {@link IAbstractFolder}. * * @param folder The {@link IAbstractFolder} object. * @return the {@link ResourceFolder} or null if it was not found. */ @Nullable public ResourceFolder getResourceFolder(@NonNull IAbstractFolder folder) { ensureInitialized(); Collection<List<ResourceFolder>> values = mFolderMap.values(); for (List<ResourceFolder> list : values) { for (ResourceFolder resFolder : list) { IAbstractFolder wrapper = resFolder.getFolder(); if (wrapper.equals(folder)) { return resFolder; } } } return null; }
/** * Processes a folder and adds it to the list of existing folders. * * @param folder the folder to process * @return the ResourceFolder created from this folder, or null if the process failed. */ @Nullable public ResourceFolder processFolder(@NonNull IAbstractFolder folder) { ensureInitialized(); // split the name of the folder in segments. String[] folderSegments = folder.getName().split(SdkConstants.RES_QUALIFIER_SEP); // get the enum for the resource type. ResourceFolderType type = ResourceFolderType.getTypeByName(folderSegments[0]); if (type != null) { // get the folder configuration. FolderConfiguration config = FolderConfiguration.getConfig(folderSegments); if (config != null) { return add(type, config, folder); } } return null; }
/** * 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); } }