use of com.android.ide.common.resources.configuration.FolderConfiguration in project android by JetBrains.
the class ThemeAttributeResolver method resolveFromInheritance.
private void resolveFromInheritance(@NotNull ThemeEditorStyle themeEditorStyle, @NotNull FolderConfiguration configuration, @NotNull RestrictedConfiguration restricted, @NotNull Set<String> seenAttributes) {
RestrictedConfiguration styleRestricted = getRestrictedConfiguration(themeEditorStyle, configuration);
if (styleRestricted == null) {
LOG.warn(configuration + " is unreachable");
return;
}
styleRestricted = restricted.intersect(styleRestricted);
if (styleRestricted == null) {
return;
}
Set<String> newSeenAttributes = new HashSet<String>(seenAttributes);
for (ItemResourceValue item : themeEditorStyle.getValues(configuration)) {
String itemName = ResolutionUtils.getQualifiedItemName(item);
if (!newSeenAttributes.contains(itemName)) {
myItemValueMap.putValue(itemName, ConfiguredElement.create(styleRestricted.getAny(), item));
newSeenAttributes.add(itemName);
}
}
String parentName = themeEditorStyle.getParentName(configuration);
if (parentName == null) {
// We have reached the top of the theme hierarchy (i.e "android:Theme")
return;
}
ThemeEditorStyle parent = new ThemeEditorStyle(myManager, parentName);
for (FolderConfiguration folder : parent.getFolders()) {
resolveFromInheritance(parent, folder, styleRestricted, newSeenAttributes);
}
}
use of com.android.ide.common.resources.configuration.FolderConfiguration in project android by JetBrains.
the class MigrateDrawableToMipmapFix method apply.
@Override
public void apply(@NotNull PsiElement startElement, @NotNull PsiElement endElement, @NotNull AndroidQuickfixContexts.Context context) {
Project project = startElement.getProject();
AndroidFacet facet = AndroidFacet.getInstance(startElement);
if (facet == null) {
return;
}
final List<PsiFile> bitmaps = Lists.newArrayList();
final Set<PsiElement> references = Sets.newHashSet();
GlobalSearchScope useScope = GlobalSearchScope.projectScope(project);
ProjectResourceRepository projectResources = facet.getProjectResources(true);
List<ResourceItem> resourceItems = projectResources.getResourceItem(myUrl.type, myUrl.name);
if (resourceItems != null) {
for (ResourceItem item : resourceItems) {
PsiFile file = LocalResourceRepository.getItemPsiFile(project, item);
if (file == null) {
continue;
}
bitmaps.add(file);
Iterable<PsiReference> allReferences = SearchUtils.findAllReferences(file, useScope);
for (PsiReference next : allReferences) {
PsiElement element = next.getElement();
if (element != null) {
references.add(element);
}
}
}
}
PsiField[] resourceFields = AndroidResourceUtil.findResourceFields(facet, ResourceType.DRAWABLE.getName(), myUrl.name, true);
if (resourceFields.length == 1) {
Iterable<PsiReference> allReferences = SearchUtils.findAllReferences(resourceFields[0], useScope);
for (PsiReference next : allReferences) {
PsiElement element = next.getElement();
if (element != null) {
references.add(element);
}
}
}
Set<PsiFile> applicableFiles = Sets.newHashSet();
applicableFiles.addAll(bitmaps);
for (PsiElement element : references) {
PsiFile containingFile = element.getContainingFile();
if (containingFile != null) {
applicableFiles.add(containingFile);
}
}
WriteCommandAction<Void> action = new WriteCommandAction<Void>(project, "Migrate Drawable to Bitmap", applicableFiles.toArray(new PsiFile[applicableFiles.size()])) {
@Override
protected void run(@NotNull Result<Void> result) throws Throwable {
// Move each drawable bitmap from drawable-my-qualifiers to bitmap-my-qualifiers
for (PsiFile bitmap : bitmaps) {
VirtualFile file = bitmap.getVirtualFile();
if (file == null) {
continue;
}
VirtualFile parent = file.getParent();
if (parent == null) {
// shouldn't happen for bitmaps found in the resource repository
continue;
}
if (file.getFileType() == StdFileTypes.XML && parent.getName().startsWith(FD_RES_VALUES)) {
// Resource alias rather than an actual drawable XML file: update the type reference instead
XmlFile xmlFile = (XmlFile) bitmap;
XmlTag root = xmlFile.getRootTag();
if (root != null) {
for (XmlTag item : root.getSubTags()) {
String name = item.getAttributeValue(ATTR_NAME);
if (myUrl.name.equals(name)) {
if (ResourceType.DRAWABLE.getName().equals(item.getName())) {
item.setName(ResourceType.MIPMAP.getName());
} else if (ResourceType.DRAWABLE.getName().equals(item.getAttributeValue(ATTR_TYPE))) {
item.setAttribute(ATTR_TYPE, ResourceType.MIPMAP.getName());
}
}
}
}
// Don't move the file
continue;
}
VirtualFile res = parent.getParent();
if (res == null) {
// shouldn't happen for bitmaps found in the resource repository
continue;
}
FolderConfiguration configuration = FolderConfiguration.getConfigForFolder(parent.getName());
if (configuration == null) {
continue;
}
String targetFolderName = configuration.getFolderName(ResourceFolderType.MIPMAP);
VirtualFile targetFolder = res.findChild(targetFolderName);
if (targetFolder == null) {
targetFolder = res.createChildDirectory(this, targetFolderName);
}
file.move(this, targetFolder);
}
// Update references
for (PsiElement reference : references) {
if (reference instanceof XmlAttributeValue) {
// Convert @drawable/foo references to @mipmap/foo
XmlAttributeValue value = (XmlAttributeValue) reference;
XmlAttribute attribute = (XmlAttribute) value.getParent();
attribute.setValue(ResourceUrl.create(ResourceType.MIPMAP, myUrl.name, false, false).toString());
} else if (reference instanceof PsiReferenceExpression) {
// Convert R.drawable.foo references to R.mipmap.foo
PsiReferenceExpression inner = (PsiReferenceExpression) reference;
PsiExpression qualifier = inner.getQualifierExpression();
if (qualifier instanceof PsiReferenceExpression) {
PsiReferenceExpression outer = (PsiReferenceExpression) qualifier;
if (outer.getReferenceNameElement() instanceof PsiIdentifier) {
PsiIdentifier identifier = (PsiIdentifier) outer.getReferenceNameElement();
if (ResourceType.DRAWABLE.getName().equals(identifier.getText())) {
Project project = reference.getProject();
final PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project);
PsiIdentifier newIdentifier = elementFactory.createIdentifier(ResourceType.MIPMAP.getName());
identifier.replace(newIdentifier);
}
}
}
}
}
}
};
action.execute();
}
use of com.android.ide.common.resources.configuration.FolderConfiguration in project android by JetBrains.
the class ResourceFolderRepository method rescanImmediately.
private void rescanImmediately(@NonNull final PsiFile psiFile, @NonNull final ResourceFolderType folderType) {
if (!ApplicationManager.getApplication().isReadAccessAllowed()) {
ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override
public void run() {
rescanImmediately(psiFile, folderType);
}
});
return;
}
PsiFile file = psiFile;
if (folderType == VALUES) {
// For unit test tracking purposes only
//noinspection AssignmentToStaticFieldFromInstanceMethod
ourFullRescans++;
// First delete out the previous items
ResourceFile resourceFile = myResourceFiles.get(file.getVirtualFile());
boolean removed = false;
if (resourceFile != null) {
for (ResourceItem item : resourceFile.getItems()) {
// Will throw away file
removed |= removeItems(resourceFile, item.getType(), item.getName(), false);
}
myResourceFiles.remove(file.getVirtualFile());
}
file = ensureValid(file);
boolean added = false;
if (file != null) {
// Add items for this file
PsiDirectory parent = file.getParent();
// since we have a folder type
assert parent != null;
String dirName = parent.getName();
PsiDirectory fileParent = psiFile.getParent();
if (fileParent != null) {
FolderConfiguration folderConfiguration = FolderConfiguration.getConfigForFolder(fileParent.getName());
if (folderConfiguration != null) {
added = scanValueFileAsPsi(getQualifiers(dirName), file, folderConfiguration);
}
}
}
if (added || removed) {
// TODO: Consider doing a deeper diff of the changes to the resource items
// to determine if the removed and added items actually differ
myGeneration = ourModificationCounter.incrementAndGet();
invalidateItemCaches();
}
} else {
ResourceFile resFile = myResourceFiles.get(file.getVirtualFile());
// If the old file was a PsiResourceFile, we could try to update ID ResourceItems in place.
if (resFile != null && resFile instanceof PsiResourceFile) {
PsiResourceFile resourceFile = (PsiResourceFile) resFile;
// in that case we may need to update the id's
if (FolderTypeRelationship.isIdGeneratingFolderType(folderType) && file.getFileType() == StdFileTypes.XML) {
// For unit test tracking purposes only
//noinspection AssignmentToStaticFieldFromInstanceMethod
ourFullRescans++;
// We've already seen this resource, so no change in the ResourceItem for the
// file itself (e.g. @layout/foo from layout-land/foo.xml). However, we may have
// to update the id's:
Set<String> idsBefore = Sets.newHashSet();
Set<String> idsAfter = Sets.newHashSet();
ListMultimap<String, ResourceItem> map = myItems.get(ResourceType.ID);
if (map != null) {
List<ResourceItem> idItems = Lists.newArrayList();
for (ResourceItem item : resourceFile) {
if (item.getType() == ResourceType.ID) {
idsBefore.add(item.getName());
idItems.add(item);
}
}
for (String id : idsBefore) {
// Note that ResourceFile has a flat map (not a multimap) so it doesn't
// record all items (unlike the myItems map) so we need to remove the map
// items manually, can't just do map.remove(item.getName(), item)
List<ResourceItem> mapItems = map.get(id);
if (mapItems != null && !mapItems.isEmpty()) {
List<ResourceItem> toDelete = Lists.newArrayListWithExpectedSize(mapItems.size());
for (ResourceItem mapItem : mapItems) {
if (mapItem.getSource() == resourceFile) {
toDelete.add(mapItem);
}
}
for (ResourceItem delete : toDelete) {
map.remove(delete.getName(), delete);
}
}
}
resourceFile.removeItems(idItems);
}
// Add items for this file
List<ResourceItem> idItems = Lists.newArrayList();
file = ensureValid(file);
if (file != null) {
addIds(idItems, file);
}
if (!idItems.isEmpty()) {
resourceFile.addItems(idItems);
for (ResourceItem item : idItems) {
idsAfter.add(item.getName());
}
}
if (!idsBefore.equals(idsAfter)) {
myGeneration = ourModificationCounter.incrementAndGet();
}
scanDataBinding(resourceFile, myGeneration);
// Identities may have changed even if the ids are the same, so update maps
invalidateItemCaches(ResourceType.ID);
}
} else {
// Remove old items first, if switching to Psi. Rescan below to add back, but with a possibly different multimap list order.
boolean switchingToPsi = resFile != null && !(resFile instanceof PsiResourceFile);
if (switchingToPsi) {
removeItemsFromFile(resFile);
}
// For unit test tracking purposes only
//noinspection AssignmentToStaticFieldFromInstanceMethod
ourFullRescans++;
PsiDirectory parent = file.getParent();
// since we have a folder type
assert parent != null;
String dirName = parent.getName();
List<ResourceType> resourceTypes = FolderTypeRelationship.getRelatedResourceTypes(folderType);
assert resourceTypes.size() >= 1 : folderType;
ResourceType type = resourceTypes.get(0);
boolean idGeneratingFolder = FolderTypeRelationship.isIdGeneratingFolderType(folderType);
ListMultimap<String, ResourceItem> map = getMap(type, true);
file = ensureValid(file);
if (file != null) {
PsiDirectory fileParent = psiFile.getParent();
if (fileParent != null) {
FolderConfiguration folderConfiguration = FolderConfiguration.getConfigForFolder(fileParent.getName());
if (folderConfiguration != null) {
boolean idGeneratingFile = idGeneratingFolder && file.getFileType() == StdFileTypes.XML;
scanFileResourceFileAsPsi(getQualifiers(dirName), folderType, folderConfiguration, type, idGeneratingFile, map, file);
}
}
myGeneration = ourModificationCounter.incrementAndGet();
invalidateItemCaches();
}
}
}
}
use of com.android.ide.common.resources.configuration.FolderConfiguration in project android by JetBrains.
the class ConfigurationManager method createSimilar.
/**
* Similar to {@link #getConfiguration(VirtualFile)}, but creates a configuration
* for a file known to be new, and crucially, bases the configuration on the existing configuration
* for a known file. This is intended for when you fork a layout, and you expect the forked layout
* to have a configuration that is (as much as possible) similar to the configuration of the
* forked file. For example, if you create a landscape version of a layout, it will preserve the
* screen size, locale, theme and render target of the existing layout.
*
* @param file the file to create a configuration for
* @param baseFile the other file to base the configuration on
* @return the new configuration
*/
@NotNull
public Configuration createSimilar(@NotNull VirtualFile file, @NotNull VirtualFile baseFile) {
ConfigurationStateManager stateManager = getStateManager();
ConfigurationFileState fileState = stateManager.getConfigurationState(baseFile);
FolderConfiguration config = FolderConfiguration.getConfigForFolder(file.getParent().getName());
if (config == null) {
config = new FolderConfiguration();
}
Configuration configuration = Configuration.create(this, file, fileState, config);
Configuration baseConfig = myCache.get(file);
if (baseConfig != null) {
configuration.setEffectiveDevice(baseConfig.getDevice(), baseConfig.getDeviceState());
}
LocalResourceRepository resources = AppResourceRepository.getAppResources(myModule, true);
ConfigurationMatcher matcher = new ConfigurationMatcher(configuration, resources, file);
matcher.adaptConfigSelection(true);
myCache.put(file, configuration);
return configuration;
}
use of com.android.ide.common.resources.configuration.FolderConfiguration in project android by JetBrains.
the class ResourceResolverCache method replaceDrawableBitmaps.
/**
* Replaces drawable bitmaps with those from the real older target. This helps the simulated platform look more genuine,
* since a lot of the look comes from the nine patch assets. For example, when used to simulate Froyo, the checkboxes
* will look better than if we use the current classic theme assets, which look like gingerbread.
*/
private static void replaceDrawableBitmaps(@NotNull Map<ResourceType, ResourceValueMap> frameworkResources, @NotNull IAndroidTarget from, @NotNull IAndroidTarget realTarget) {
// This is a bit hacky; we should be operating at the resource repository level rather than
// for configured resources. However, we may not need this for very long.
ResourceValueMap map = frameworkResources.get(ResourceType.DRAWABLE);
String oldPrefix = from.getPath(IAndroidTarget.RESOURCES);
String newPrefix = realTarget.getPath(IAndroidTarget.RESOURCES);
if (map == null || map.isEmpty() || oldPrefix == null || newPrefix == null || oldPrefix.equals(newPrefix)) {
return;
}
Collection<ResourceValue> values = map.values();
Map<String, String> densityDirMap = Maps.newHashMap();
// Leave XML drawable resources alone since they can reference nonexistent colors and other resources
// not available in the real rendering platform
final boolean ONLY_REPLACE_BITMAPS = true;
Density[] densities = Density.values();
for (ResourceValue value : values) {
String v = value.getValue();
//noinspection ConstantConditions,PointlessBooleanExpression
if (v != null && (!ONLY_REPLACE_BITMAPS || v.endsWith(DOT_PNG))) {
if (v.startsWith(oldPrefix)) {
String relative = v.substring(oldPrefix.length());
if (v.endsWith(DOT_PNG)) {
int index = relative.indexOf(File.separatorChar);
if (index == -1) {
index = relative.indexOf('/');
}
if (index == -1) {
continue;
}
String parent = relative.substring(0, index);
String replace = densityDirMap.get(parent);
if (replace == null) {
FolderConfiguration configuration = FolderConfiguration.getConfigForFolder(parent);
if (configuration != null) {
DensityQualifier densityQualifier = configuration.getDensityQualifier();
if (densityQualifier != null) {
Density density = densityQualifier.getValue();
if (!new File(newPrefix, parent).exists()) {
String oldQualifier = SdkConstants.RES_QUALIFIER_SEP + density.getResourceValue();
String matched = null;
for (Density d : densities) {
if (d.ordinal() <= density.ordinal()) {
// No reason to check higher
continue;
}
String newQualifier = SdkConstants.RES_QUALIFIER_SEP + d.getResourceValue();
String newName = parent.replace(oldQualifier, newQualifier);
File dir = new File(newPrefix, newName);
if (dir.exists()) {
matched = newName;
break;
}
}
if (matched == null) {
continue;
}
replace = matched;
// This isn't right; there may be some assets only in mdpi!
densityDirMap.put(parent, replace);
}
}
}
}
relative = replace + relative.substring(index);
}
File newFile = new File(newPrefix, relative);
if (newFile.exists()) {
value.setValue(newFile.getPath());
}
}
}
}
}
Aggregations