Search in sources :

Example 11 with FolderConfiguration

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);
    }
}
Also used : ItemResourceValue(com.android.ide.common.rendering.api.ItemResourceValue) ThemeEditorStyle(com.android.tools.idea.editors.theme.datamodels.ThemeEditorStyle) ConfiguredThemeEditorStyle(com.android.tools.idea.editors.theme.datamodels.ConfiguredThemeEditorStyle) FolderConfiguration(com.android.ide.common.resources.configuration.FolderConfiguration) RestrictedConfiguration(com.android.tools.idea.editors.theme.qualifiers.RestrictedConfiguration)

Example 12 with FolderConfiguration

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();
}
Also used : WriteCommandAction(com.intellij.openapi.command.WriteCommandAction) VirtualFile(com.intellij.openapi.vfs.VirtualFile) XmlAttribute(com.intellij.psi.xml.XmlAttribute) NotNull(org.jetbrains.annotations.NotNull) Result(com.intellij.openapi.application.Result) GlobalSearchScope(com.intellij.psi.search.GlobalSearchScope) ProjectResourceRepository(com.android.tools.idea.res.ProjectResourceRepository) XmlFile(com.intellij.psi.xml.XmlFile) FolderConfiguration(com.android.ide.common.resources.configuration.FolderConfiguration) XmlAttributeValue(com.intellij.psi.xml.XmlAttributeValue) AndroidFacet(org.jetbrains.android.facet.AndroidFacet) Project(com.intellij.openapi.project.Project) ResourceItem(com.android.ide.common.res2.ResourceItem) XmlTag(com.intellij.psi.xml.XmlTag)

Example 13 with FolderConfiguration

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();
            }
        }
    }
}
Also used : ResourceType(com.android.resources.ResourceType) FolderConfiguration(com.android.ide.common.resources.configuration.FolderConfiguration)

Example 14 with FolderConfiguration

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;
}
Also used : FolderConfiguration(com.android.ide.common.resources.configuration.FolderConfiguration) LocalResourceRepository(com.android.tools.idea.res.LocalResourceRepository) FolderConfiguration(com.android.ide.common.resources.configuration.FolderConfiguration) NotNull(org.jetbrains.annotations.NotNull)

Example 15 with FolderConfiguration

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());
                }
            }
        }
    }
}
Also used : ResourceValue(com.android.ide.common.rendering.api.ResourceValue) FolderConfiguration(com.android.ide.common.resources.configuration.FolderConfiguration) Density(com.android.resources.Density) File(java.io.File) DensityQualifier(com.android.ide.common.resources.configuration.DensityQualifier) ResourceValueMap(com.android.ide.common.resources.ResourceValueMap)

Aggregations

FolderConfiguration (com.android.ide.common.resources.configuration.FolderConfiguration)69 VirtualFile (com.intellij.openapi.vfs.VirtualFile)18 NotNull (org.jetbrains.annotations.NotNull)14 VersionQualifier (com.android.ide.common.resources.configuration.VersionQualifier)12 AndroidFacet (org.jetbrains.android.facet.AndroidFacet)12 Nullable (org.jetbrains.annotations.Nullable)12 ResourceItem (com.android.ide.common.res2.ResourceItem)10 LocaleQualifier (com.android.ide.common.resources.configuration.LocaleQualifier)10 DensityQualifier (com.android.ide.common.resources.configuration.DensityQualifier)9 ResourceFolderType (com.android.resources.ResourceFolderType)9 ResourceValue (com.android.ide.common.rendering.api.ResourceValue)7 IAndroidTarget (com.android.sdklib.IAndroidTarget)7 Project (com.intellij.openapi.project.Project)7 ItemResourceValue (com.android.ide.common.rendering.api.ItemResourceValue)6 ResourceResolver (com.android.ide.common.resources.ResourceResolver)6 LayoutDirectionQualifier (com.android.ide.common.resources.configuration.LayoutDirectionQualifier)6 ScreenOrientationQualifier (com.android.ide.common.resources.configuration.ScreenOrientationQualifier)6 ScreenSizeQualifier (com.android.ide.common.resources.configuration.ScreenSizeQualifier)6 SessionParams (com.android.ide.common.rendering.api.SessionParams)5 CountryCodeQualifier (com.android.ide.common.resources.configuration.CountryCodeQualifier)5