do not resolve/complete android private system resources

This commit is contained in:
Eugene Kudelevsky
2012-07-23 14:53:48 +04:00
parent 09cafea142
commit 8afc4486fa
17 changed files with 231 additions and 88 deletions
@@ -51,8 +51,8 @@ import org.jetbrains.android.actions.CreateXmlResourceDialog;
import org.jetbrains.android.dom.resources.ResourceElement;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.facet.AndroidRootUtil;
import org.jetbrains.android.resourceManagers.FileResourceProcessor;
import org.jetbrains.android.resourceManagers.ResourceManager;
import org.jetbrains.android.util.AndroidCommonUtils;
import org.jetbrains.android.util.AndroidResourceUtil;
import org.jetbrains.android.util.AndroidUtils;
import org.jetbrains.annotations.Nls;
@@ -603,25 +603,23 @@ public class ResourceDialog extends DialogWrapper implements TreeSelectionListen
public ResourceGroup(ResourceType type, ResourceManager manager) {
myType = type;
String resourceType = type.getName();
final String resourceType = type.getName();
Collection<String> resourceNames = manager.getValueResourceNames(resourceType);
for (String resourceName : resourceNames) {
myItems.add(new ResourceItem(this, resourceName, null, RESOURCE_ITEM_ICON));
}
final Set<String> fileNames = new HashSet<String>();
Set<String> fileNames = new HashSet<String>();
List<VirtualFile> dirs = manager.getResourceSubdirs(resourceType);
for (VirtualFile dir : dirs) {
for (VirtualFile resourceFile : dir.getChildren()) {
if (!resourceFile.isDirectory()) {
String fileName = AndroidCommonUtils.getResourceName(resourceType, resourceFile.getName());
if (fileNames.add(fileName)) {
myItems.add(new ResourceItem(this, fileName, resourceFile, resourceFile.getFileType().getIcon()));
}
manager.processFileResources(resourceType, new FileResourceProcessor() {
@Override
public boolean process(@NotNull VirtualFile resFile, @NotNull String resName, @NotNull String resFolderType) {
if (fileNames.add(resName)) {
myItems.add(new ResourceItem(ResourceGroup.this, resName, resFile, resFile.getFileType().getIcon()));
}
return true;
}
}
});
if (type == ResourceType.ID) {
for (String id : manager.getIds()) {
@@ -4,11 +4,8 @@ import com.android.resources.ResourceType;
import com.android.sdklib.IAndroidTarget;
import com.intellij.openapi.compiler.ValidityState;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.roots.ContentIterator;
import com.intellij.openapi.roots.impl.FileIndexImplUtil;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileFilter;
import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.HashMap;
import org.jetbrains.android.dom.resources.DeclareStyleable;
@@ -16,6 +13,7 @@ import org.jetbrains.android.dom.resources.ResourceElement;
import org.jetbrains.android.dom.resources.Resources;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.facet.AndroidRootUtil;
import org.jetbrains.android.resourceManagers.FileResourceProcessor;
import org.jetbrains.android.resourceManagers.LocalResourceManager;
import org.jetbrains.android.sdk.AndroidPlatform;
import org.jetbrains.android.util.AndroidCommonUtils;
@@ -74,31 +72,24 @@ public class ResourceNamesValidityState implements ValidityState {
}
}
for (final VirtualFile subdir : manager.getResourceSubdirs(null)) {
final String subdirName = subdir.getName();
final int index = subdirName.indexOf('-');
final String typeName = index >= 0 ? subdirName.substring(0, index) : subdirName;
final ResourceType type = ResourceType.getEnum(typeName);
final boolean idProvidingResource = type != null && ArrayUtil.find(AndroidCommonUtils.ID_PROVIDING_RESOURCE_TYPES, type) >= 0;
manager.processFileResources(null, new FileResourceProcessor() {
@Override
public boolean process(@NotNull VirtualFile resFile, @NotNull String resName, @NotNull String resFolderType) {
final ResourceType type = ResourceType.getEnum(resFolderType);
final boolean idProvidingResource = type != null && ArrayUtil.find(AndroidCommonUtils.ID_PROVIDING_RESOURCE_TYPES, type) >= 0;
FileIndexImplUtil.iterateRecursively(subdir, VirtualFileFilter.ALL, new ContentIterator() {
@Override
public boolean processFile(VirtualFile fileOrDir) {
if (!fileOrDir.isDirectory()) {
ResourceFileData data = myResources.get(fileOrDir.getPath());
if (data == null) {
data = new ResourceFileData();
myResources.put(fileOrDir.getPath(), data);
}
if (idProvidingResource) {
data.setTimestamp(fileOrDir.getTimeStamp());
}
}
return true;
ResourceFileData data = myResources.get(resFile.getPath());
if (data == null) {
data = new ResourceFileData();
myResources.put(resFile.getPath(), data);
}
});
}
if (idProvidingResource) {
data.setTimestamp(resFile.getTimeStamp());
}
return true;
}
});
}
private static void addValueResources(VirtualFile file,
@@ -33,9 +33,9 @@ import org.jetbrains.android.dom.resources.ResourceValue;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.inspections.CreateFileResourceQuickFix;
import org.jetbrains.android.inspections.CreateValueResourceQuickFix;
import org.jetbrains.android.resourceManagers.FileResourceProcessor;
import org.jetbrains.android.resourceManagers.LocalResourceManager;
import org.jetbrains.android.resourceManagers.ResourceManager;
import org.jetbrains.android.util.AndroidCommonUtils;
import org.jetbrains.android.util.AndroidResourceUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -164,13 +164,15 @@ public class ResourceReferenceConverter extends ResolvingConverter<ResourceValue
final Set<String> result = new HashSet<String>();
final LocalResourceManager manager = facet.getLocalResourceManager();
for (VirtualFile resSubdir : manager.getResourceSubdirs(null)) {
final String resType = AndroidCommonUtils.getResourceTypeByDirName(resSubdir.getName());
if (resType != null && ResourceType.getEnum(resType) != null) {
result.add(resType);
manager.processFileResources(null, new FileResourceProcessor() {
@Override
public boolean process(@NotNull VirtualFile resFile, @NotNull String resName, @NotNull String resFolderType) {
if (ResourceType.getEnum(resFolderType) != null) {
result.add(resFolderType);
}
return true;
}
}
});
result.addAll(manager.getValueResourceTypes());
if (manager.getIds().size() > 0) {
@@ -0,0 +1,11 @@
package org.jetbrains.android.resourceManagers;
import com.intellij.openapi.vfs.VirtualFile;
import org.jetbrains.annotations.NotNull;
/**
* @author Eugene.Kudelevsky
*/
public interface FileResourceProcessor {
boolean process(@NotNull VirtualFile resFile, @NotNull String resName, @NotNull String resFolderType);
}
@@ -75,6 +75,30 @@ public abstract class ResourceManager {
@Nullable
public abstract VirtualFile getResourceDir();
public boolean processFileResources(@Nullable String resourceType, @NotNull FileResourceProcessor processor) {
return processFileResources(resourceType, processor, true);
}
public boolean processFileResources(@Nullable String resourceType, @NotNull FileResourceProcessor processor, boolean publicOnly) {
for (VirtualFile resSubdir : getResourceSubdirs(resourceType)) {
final String resType = AndroidCommonUtils.getResourceTypeByDirName(resSubdir.getName());
if (resType != null) {
assert resourceType == null || resourceType.equals(resType);
for (VirtualFile resFile : resSubdir.getChildren()) {
final String resName = AndroidCommonUtils.getResourceName(resType, resFile.getName());
if (!resFile.isDirectory() && (!publicOnly || isResourcePublic(resType, resName))) {
if (!processor.process(resFile, resName, resType)) {
return false;
}
}
}
}
}
return true;
}
public boolean isResourceDir(@NotNull VirtualFile dir) {
return dir.equals(getResourceDir());
}
@@ -84,38 +108,44 @@ public abstract class ResourceManager {
return VirtualFile.EMPTY_ARRAY;
}
protected boolean isResourcePublic(@NotNull String type, @NotNull String name) {
return true;
}
@NotNull
public List<VirtualFile> getResourceSubdirs(@Nullable String resourceType) {
return AndroidResourceUtil.getResourceSubdirs(resourceType, getAllResourceDirs());
}
@NotNull
public List<PsiFile> findResourceFiles(@NotNull String resType,
@Nullable String resName,
boolean distinguishDelimetersInName,
@NotNull String... extensions) {
List<PsiFile> result = new ArrayList<PsiFile>();
Set<String> extensionSet = new HashSet<String>();
public List<PsiFile> findResourceFiles(@NotNull final String resType1,
@Nullable final String resName1,
final boolean distinguishDelimetersInName,
@NotNull final String... extensions) {
final List<PsiFile> result = new ArrayList<PsiFile>();
final Set<String> extensionSet = new HashSet<String>();
addAll(extensionSet, extensions);
for (VirtualFile dir : getResourceSubdirs(resType)) {
for (final VirtualFile resFile : dir.getChildren()) {
String extension = resFile.getExtension();
if (extensions.length == 0 || extensionSet.contains(extension)) {
String s = AndroidCommonUtils.getResourceName(resType, resFile.getName());
if (resName == null || AndroidUtils.equal(resName, s, distinguishDelimetersInName)) {
PsiFile file = ApplicationManager.getApplication().runReadAction(new Computable<PsiFile>() {
@Nullable
public PsiFile compute() {
return PsiManager.getInstance(myModule.getProject()).findFile(resFile);
}
});
if (file != null) {
result.add(file);
processFileResources(resType1, new FileResourceProcessor() {
@Override
public boolean process(@NotNull final VirtualFile resFile, @NotNull String resName, @NotNull String resFolderType) {
final String extension = resFile.getExtension();
if ((extensions.length == 0 || extensionSet.contains(extension)) &&
(resName1 == null || AndroidUtils.equal(resName1, resName, distinguishDelimetersInName))) {
final PsiFile file = ApplicationManager.getApplication().runReadAction(new Computable<PsiFile>() {
@Nullable
public PsiFile compute() {
return PsiManager.getInstance(myModule.getProject()).findFile(resFile);
}
});
if (file != null) {
result.add(file);
}
}
return true;
}
}
});
return result;
}
@@ -171,7 +201,14 @@ public abstract class ResourceManager {
if (!resources.isValid() || myModule.isDisposed() || myModule.getProject().isDisposed()) {
return;
}
result.addAll(AndroidResourceUtil.getValueResourcesFromElement(resourceType, resources));
final List<ResourceElement> valueResources = AndroidResourceUtil.getValueResourcesFromElement(resourceType, resources);
for (ResourceElement valueResource : valueResources) {
final String resName = valueResource.getName().getValue();
if (resName != null && isResourcePublic(resourceType, resName)) {
result.add(valueResource);
}
}
}
});
}
@@ -207,15 +244,16 @@ public abstract class ResourceManager {
}
@NotNull
public Set<String> getFileResourcesNames(@NotNull String resourceType) {
Set<String> result = new HashSet<String>();
List<VirtualFile> dirs = getResourceSubdirs(resourceType);
for (VirtualFile dir : dirs) {
for (VirtualFile resourceFile : dir.getChildren()) {
if (resourceFile.isDirectory()) continue;
result.add(AndroidCommonUtils.getResourceName(resourceType, resourceFile.getName()));
public Set<String> getFileResourcesNames(@NotNull final String resourceType) {
final Set<String> result = new HashSet<String>();
processFileResources(resourceType, new FileResourceProcessor() {
@Override
public boolean process(@NotNull VirtualFile resFile, @NotNull String resName, @NotNull String resFolderType) {
result.add(resName);
return true;
}
}
});
return result;
}
@@ -269,7 +307,9 @@ public abstract class ResourceManager {
if (entries != null) {
for (ResourceEntry entry : entries) {
result.add(entry);
if (isResourcePublic(entry.getType(), entry.getName())) {
result.add(entry);
}
}
}
}
@@ -293,6 +333,10 @@ public abstract class ResourceManager {
// searches only declarations such as "@+id/..."
@Nullable
public List<PsiElement> findIdDeclarations(@NotNull final String id) {
if (!isResourcePublic(ResourceType.ID.getName(), id)) {
return Collections.emptyList();
}
final List<PsiElement> declarations = new ArrayList<PsiElement>();
final Collection<VirtualFile> files =
FileBasedIndex.getInstance().getContainingFiles(AndroidIdIndex.INDEX_ID, id, GlobalSearchScope.allScope(myModule.getProject()));
@@ -357,9 +401,13 @@ public abstract class ResourceManager {
for (VirtualFile resSubdir : getResourceSubdirsToSearchIds()) {
for (VirtualFile resFile : resSubdir.getChildren()) {
final Set<String> ids = file2ids.get(resFile);
if (ids != null) {
result.addAll(ids);
for (String id : ids) {
if (isResourcePublic(ResourceType.ID.getName(), id)) {
result.add(id);
}
}
}
}
}
@@ -16,25 +16,84 @@
package org.jetbrains.android.resourceManagers;
import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.SdkConstants;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.JavaPsiFacade;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiField;
import com.intellij.util.containers.HashMap;
import com.intellij.util.containers.HashSet;
import com.intellij.util.xml.ConvertContext;
import org.jetbrains.android.dom.attrs.AttributeDefinitions;
import org.jetbrains.android.facet.AndroidFacet;
import org.jetbrains.android.sdk.AndroidPlatform;
import org.jetbrains.android.sdk.AndroidTargetData;
import org.jetbrains.android.util.AndroidResourceUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Map;
import java.util.Set;
/**
* @author coyote
*/
public class SystemResourceManager extends ResourceManager {
private final AndroidPlatform myPlatform;
private final Map<String, Set<String>> myPublicResourcesCache = new HashMap<String, Set<String>>();
public SystemResourceManager(@NotNull AndroidFacet facet, @NotNull AndroidPlatform androidPlatform) {
super(facet);
myPlatform = androidPlatform;
final Module module = facet.getModule();
ApplicationManager.getApplication().runReadAction(new Runnable() {
@Override
public void run() {
buildPublicResourceCache(module);
}
});
}
private void buildPublicResourceCache(@NotNull Module module) {
final PsiClass rClass = JavaPsiFacade.getInstance(module.getProject())
.findClass(SdkConstants.CLASS_R, module.getModuleWithDependenciesAndLibrariesScope(false));
if (rClass == null) {
return;
}
for (PsiClass resourceClass : rClass.getInnerClasses()) {
final String resType = resourceClass.getName();
if (resType != null) {
Set<String> resNameSet = myPublicResourcesCache.get(resType);
if (resNameSet == null) {
resNameSet = new HashSet<String>();
myPublicResourcesCache.put(resType, resNameSet);
}
for (PsiField resField : resourceClass.getFields()) {
final String resName = resField.getName();
if (resName != null) {
resNameSet.add(resName);
}
}
}
}
}
protected boolean isResourcePublic(@NotNull String type, @NotNull String name) {
final Set<String> fieldNames = myPublicResourcesCache.get(type);
if (fieldNames == null || fieldNames.isEmpty()) {
return false;
}
final String fieldName = AndroidResourceUtil.getFieldNameByResourceName(name);
return fieldNames.contains(fieldName);
}
@NotNull
+2 -2
View File
@@ -1,12 +1,12 @@
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:interpolator="@android:interpolator/platformInterpolator"
android:interpolator="@android:interpolator/accelerate_cubic"
android:valueFrom="100dp" android:valueTo="0dp"
android:valueType="floatType"
android:propertyName="translationX"
android:duration="@android:integer/config_mediumAnimTime" />
<animator
android:interpolator="@android:interpolator/platformInterpolator"
android:interpolator="@android:interpolator/accelerate_cubic"
android:valueFrom="0.0" android:valueTo="1.0"
android:valueType="floatType"
android:propertyName="alpha"
@@ -0,0 +1,14 @@
<set xmlns:android="http://schemas.android.com/apk/res/android">
<objectAnimator
android:interpolator="@interpolator/myInterpolator"
android:valueFrom="100dp" android:valueTo="0dp"
android:valueType="floatType"
android:propertyName="translationX"
android:duration="@android:integer/config_mediumAnimTime" />
<animator
android:interpolator="@interpolator/myInterpolator"
android:valueFrom="0.0" android:valueTo="1.0"
android:valueType="floatType"
android:propertyName="alpha"
android:duration="@android:integer/config_mediumAnimTime" />
</set>
@@ -1,3 +1,3 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android">
<TextView android:layout_alignBaseline="@android:id/no_permiss<caret>"/>
<TextView android:layout_alignBaseline="@android:id/closeBut<caret>"/>
</RelativeLayout>
@@ -1,3 +1,3 @@
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android">
<TextView android:layout_alignBaseline="@android:id/no_permissions"/>
<TextView android:layout_alignBaseline="@android:id/closeButton"/>
</RelativeLayout>
@@ -1,3 +1,3 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
style="@android:style/WindowTitleBackground">
style="@android:style/MediaButton">
</LinearLayout>
@@ -0,0 +1,10 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="<error>@android:drawable/private</error>"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:drawable/menuitem_background"/>
</LinearLayout>
@@ -42,15 +42,21 @@ public class AndroidAnimatorDomTest extends AndroidDomTest {
toTestCompletion("root.xml", "root_after.xml");
}
public void testHighlighting() throws Throwable {
doTestHighlighting("hl.xml");
}
public void testTagNames() throws Throwable {
CamelHumpMatcher.forceStartMatching(getTestRootDisposable());
toTestCompletion("tn.xml", "tn_after.xml");
}
// todo: provide normal mock android jar and add public interpolator into it
/*public void testHighlighting() throws Throwable {
doTestHighlighting("hl.xml");
}*/
public void testHighlighting1() throws Throwable {
copyFileToProject("myInterpolator.xml", "res/interpolator/myInterpolator.xml");
doTestHighlighting("hl1.xml");
}
public void testAttributeNames() throws Throwable {
toTestCompletion("an1.xml", "an1_after.xml");
toTestCompletion("an2.xml", "an2_after.xml");
@@ -334,7 +334,7 @@ public class AndroidLayoutDomTest extends AndroidDomTest {
}
public void testIdCompletion2() throws Throwable {
doTestCompletionVariants("idcompl2.xml", "@android:id/text", "@android:id/text1", "@android:id/text2");
doTestCompletionVariants("idcompl2.xml", "@android:id/text1", "@android:id/text2");
}
public void testIdHighlighting() throws Throwable {
@@ -599,6 +599,10 @@ public class AndroidLayoutDomTest extends AndroidDomTest {
myFixture.checkResultByFile("res/drawable/unknown.xml", testFolder + '/' + getTestName(true) + "_drawable_after.xml", true);
}
public void testPrivateAndPublicResources() throws Throwable {
doTestHighlighting();
}
private void doCreateFileResourceFromUsage(VirtualFile virtualFile) {
myFixture.configureFromExistingVirtualFile(virtualFile);
final List<HighlightInfo> infos = myFixture.doHighlighting();