diff --git a/plugins/android/src/META-INF/plugin.xml b/plugins/android/src/META-INF/plugin.xml
index 4700bd2e5eec..3e202563f1a4 100644
--- a/plugins/android/src/META-INF/plugin.xml
+++ b/plugins/android/src/META-INF/plugin.xml
@@ -220,6 +220,7 @@
+
diff --git a/plugins/android/src/org/jetbrains/android/augment/AndroidLightClass.java b/plugins/android/src/org/jetbrains/android/augment/AndroidLightClass.java
new file mode 100644
index 000000000000..51f02ddcd4d5
--- /dev/null
+++ b/plugins/android/src/org/jetbrains/android/augment/AndroidLightClass.java
@@ -0,0 +1,338 @@
+package org.jetbrains.android.augment;
+
+import com.intellij.lang.java.JavaLanguage;
+import com.intellij.navigation.ItemPresentation;
+import com.intellij.navigation.ItemPresentationProviders;
+import com.intellij.openapi.util.Pair;
+import com.intellij.psi.*;
+import com.intellij.psi.impl.PsiClassImplUtil;
+import com.intellij.psi.impl.PsiImplUtil;
+import com.intellij.psi.impl.light.LightElement;
+import com.intellij.psi.impl.light.LightEmptyImplementsList;
+import com.intellij.psi.impl.light.LightModifierList;
+import com.intellij.psi.impl.light.LightTypeParameterListBuilder;
+import com.intellij.psi.javadoc.PsiDocComment;
+import com.intellij.psi.scope.PsiScopeProcessor;
+import com.intellij.psi.search.SearchScope;
+import com.intellij.util.IncorrectOperationException;
+import org.jetbrains.annotations.NonNls;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import javax.swing.*;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author Eugene.Kudelevsky
+ */
+public abstract class AndroidLightClass extends LightElement implements PsiClass, SyntheticElement {
+ private final PsiClass myContainingClass;
+ protected final String myName;
+
+ protected AndroidLightClass(@NotNull PsiClass context, @NotNull String name) {
+ super(context.getManager(), JavaLanguage.INSTANCE);
+ myContainingClass = context;
+ myName = name;
+ }
+
+ @Override
+ public String toString() {
+ return "AndroidRClass";
+ }
+
+ @Override
+ public String getQualifiedName() {
+ return myContainingClass.getQualifiedName() + '.' + myName;
+ }
+
+ @Override
+ public boolean isInterface() {
+ return false;
+ }
+
+ @Override
+ public boolean isAnnotationType() {
+ return false;
+ }
+
+ @Override
+ public boolean isEnum() {
+ return false;
+ }
+
+ @Override
+ public PsiReferenceList getExtendsList() {
+ return new LightEmptyImplementsList(myManager);
+ }
+
+ @Override
+ public PsiReferenceList getImplementsList() {
+ return new LightEmptyImplementsList(myManager);
+ }
+
+ @NotNull
+ @Override
+ public PsiClassType[] getExtendsListTypes() {
+ return PsiClassType.EMPTY_ARRAY;
+ }
+
+ @NotNull
+ @Override
+ public PsiClassType[] getImplementsListTypes() {
+ return PsiClassType.EMPTY_ARRAY;
+ }
+
+ @Override
+ public PsiClass getSuperClass() {
+ return null;
+ }
+
+ @Override
+ public PsiClass[] getInterfaces() {
+ return PsiClass.EMPTY_ARRAY;
+ }
+
+ @NotNull
+ @Override
+ public PsiClass[] getSupers() {
+ return PsiClass.EMPTY_ARRAY;
+ }
+
+ @NotNull
+ @Override
+ public PsiClassType[] getSuperTypes() {
+ return PsiClassType.EMPTY_ARRAY;
+ }
+
+ @NotNull
+ @Override
+ public abstract PsiField[] getFields();
+
+ @NotNull
+ @Override
+ public PsiMethod[] getMethods() {
+ return PsiMethod.EMPTY_ARRAY;
+ }
+
+ @NotNull
+ @Override
+ public PsiMethod[] getConstructors() {
+ return PsiMethod.EMPTY_ARRAY;
+ }
+
+ @NotNull
+ @Override
+ public PsiClass[] getInnerClasses() {
+ return PsiClass.EMPTY_ARRAY;
+ }
+
+ @NotNull
+ @Override
+ public PsiClassInitializer[] getInitializers() {
+ return PsiClassInitializer.EMPTY_ARRAY;
+ }
+
+ @NotNull
+ @Override
+ public PsiField[] getAllFields() {
+ return getFields();
+ }
+
+ @NotNull
+ @Override
+ public PsiMethod[] getAllMethods() {
+ return PsiMethod.EMPTY_ARRAY;
+ }
+
+ @NotNull
+ @Override
+ public PsiClass[] getAllInnerClasses() {
+ return PsiClass.EMPTY_ARRAY;
+ }
+
+ @Override
+ public PsiField findFieldByName(@NonNls String name, boolean checkBases) {
+ final PsiField[] fields = getFields();
+ for (final PsiField field : fields) {
+ if (name.equals(field.getName())) return field;
+ }
+ return null;
+ }
+
+ @Override
+ public PsiMethod findMethodBySignature(PsiMethod patternMethod, boolean checkBases) {
+ return null;
+ }
+
+ @NotNull
+ @Override
+ public PsiMethod[] findMethodsBySignature(PsiMethod patternMethod, boolean checkBases) {
+ return PsiMethod.EMPTY_ARRAY;
+ }
+
+ @NotNull
+ @Override
+ public PsiMethod[] findMethodsByName(@NonNls String name, boolean checkBases) {
+ return PsiMethod.EMPTY_ARRAY;
+ }
+
+ @NotNull
+ @Override
+ public List> findMethodsAndTheirSubstitutorsByName(@NonNls String name, boolean checkBases) {
+ return Collections.emptyList();
+ }
+
+ @NotNull
+ @Override
+ public List> getAllMethodsAndTheirSubstitutors() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public PsiClass findInnerClassByName(@NonNls String name, boolean checkBases) {
+ return null;
+ }
+
+ @Override
+ public PsiElement getLBrace() {
+ return null;
+ }
+
+ @Override
+ public PsiElement getRBrace() {
+ return null;
+ }
+
+ @Override
+ public PsiIdentifier getNameIdentifier() {
+ return null;
+ }
+
+ @NotNull
+ @Override
+ public PsiElement getNavigationElement() {
+ return myContainingClass;
+ }
+
+ @Nullable
+ @Override
+ public PsiElement getScope() {
+ return null;
+ }
+
+ @Override
+ public boolean isInheritor(@NotNull PsiClass baseClass, boolean checkDeep) {
+ return false;
+ }
+
+ @Override
+ public boolean isInheritorDeep(PsiClass baseClass, @Nullable PsiClass classToByPass) {
+ return false;
+ }
+
+ @Override
+ public PsiClass getContainingClass() {
+ return myContainingClass;
+ }
+
+ @NotNull
+ @Override
+ public Collection getVisibleSignatures() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public PsiElement setName(@NonNls @NotNull String name) throws IncorrectOperationException {
+ throw new IncorrectOperationException("Cannot change the name of " + getQualifiedName() + " class");
+ }
+
+ @Override
+ public PsiDocComment getDocComment() {
+ return null;
+ }
+
+ @Override
+ public boolean isDeprecated() {
+ return false;
+ }
+
+ @Override
+ public boolean hasTypeParameters() {
+ return false;
+ }
+
+ @Override
+ public PsiTypeParameterList getTypeParameterList() {
+ return new LightTypeParameterListBuilder(myManager, getLanguage());
+ }
+
+ @NotNull
+ @Override
+ public PsiTypeParameter[] getTypeParameters() {
+ return PsiTypeParameter.EMPTY_ARRAY;
+ }
+
+ @Override
+ public PsiModifierList getModifierList() {
+ return new LightModifierList(myManager, getLanguage(), PsiModifier.PUBLIC, PsiModifier.STATIC, PsiModifier.FINAL);
+ }
+
+ @Override
+ public boolean hasModifierProperty(@PsiModifier.ModifierConstant @NonNls @NotNull String name) {
+ final PsiModifierList list = getModifierList();
+ return list != null && list.hasModifierProperty(name);
+ }
+
+ @Override
+ public String getName() {
+ return myName;
+ }
+
+ @Override
+ protected boolean isVisibilitySupported() {
+ return true;
+ }
+
+ @Override
+ protected Icon getElementIcon(@IconFlags int flags) {
+ return PsiClassImplUtil.getClassIcon(flags, this);
+ }
+
+ @Override
+ public boolean isEquivalentTo(PsiElement another) {
+ return PsiClassImplUtil.isClassEquivalentTo(this, another);
+ }
+
+ @NotNull
+ @Override
+ public SearchScope getUseScope() {
+ return PsiImplUtil.getMemberUseScope(this);
+ }
+
+ @Override
+ public ItemPresentation getPresentation() {
+ return ItemPresentationProviders.getItemPresentation(this);
+ }
+
+ @Nullable
+ @Override
+ public PsiFile getContainingFile() {
+ final PsiClass containingClass = getContainingClass();
+ return containingClass == null ? null : containingClass.getContainingFile();
+ }
+
+ @Override
+ public PsiElement getParent() {
+ return myContainingClass;
+ }
+
+ @Override
+ public boolean processDeclarations(@NotNull final PsiScopeProcessor processor,
+ @NotNull final ResolveState state,
+ final PsiElement lastParent,
+ @NotNull final PsiElement place) {
+ return PsiClassImplUtil.processDeclarationsInClass(this, processor, state, null, lastParent, place, false);
+ }
+}
diff --git a/plugins/android/src/org/jetbrains/android/augment/AndroidLightField.java b/plugins/android/src/org/jetbrains/android/augment/AndroidLightField.java
new file mode 100644
index 000000000000..cf25fefa55d1
--- /dev/null
+++ b/plugins/android/src/org/jetbrains/android/augment/AndroidLightField.java
@@ -0,0 +1,28 @@
+package org.jetbrains.android.augment;
+
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.PsiType;
+import com.intellij.psi.impl.light.LightFieldBuilder;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+/**
+* @author Eugene.Kudelevsky
+*/
+class AndroidLightField extends LightFieldBuilder {
+ private final AndroidLightClass myContext;
+
+ public AndroidLightField(@NotNull String name,
+ @NotNull AndroidLightClass context,
+ @NotNull PsiType type) {
+ super(name, type, context);
+ myContext = context;
+ setContainingClass(context);
+ }
+
+ @Nullable
+ @Override
+ public PsiFile getContainingFile() {
+ return myContext.getContainingFile();
+ }
+}
diff --git a/plugins/android/src/org/jetbrains/android/augment/AndroidPsiAugmentProvider.java b/plugins/android/src/org/jetbrains/android/augment/AndroidPsiAugmentProvider.java
new file mode 100644
index 000000000000..d7a9a153bc98
--- /dev/null
+++ b/plugins/android/src/org/jetbrains/android/augment/AndroidPsiAugmentProvider.java
@@ -0,0 +1,61 @@
+package org.jetbrains.android.augment;
+
+import com.intellij.psi.PsiClass;
+import com.intellij.psi.PsiElement;
+import com.intellij.psi.PsiFile;
+import com.intellij.psi.augment.PsiAugmentProvider;
+import org.jetbrains.android.dom.converters.ResourceReferenceConverter;
+import org.jetbrains.android.facet.AndroidFacet;
+import org.jetbrains.android.util.AndroidResourceUtil;
+import org.jetbrains.android.util.AndroidUtils;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.*;
+
+/**
+ * @author Eugene.Kudelevsky
+ */
+public class AndroidPsiAugmentProvider extends PsiAugmentProvider {
+ @SuppressWarnings("unchecked")
+ @NotNull
+ @Override
+ public List getAugments(@NotNull PsiElement element, @NotNull Class type) {
+ if (type != PsiClass.class ||
+ !(element instanceof PsiClass)) {
+ return Collections.emptyList();
+ }
+ final PsiClass aClass = (PsiClass)element;
+ final String className = aClass.getName();
+
+ if (!AndroidUtils.R_CLASS_NAME.equals(className) &&
+ !AndroidUtils.MANIFEST_CLASS_NAME.equals(className)) {
+ return Collections.emptyList();
+ }
+
+ final AndroidFacet facet = AndroidFacet.getInstance(element);
+ if (facet == null) {
+ return Collections.emptyList();
+ }
+
+ final PsiFile containingFile = element.getContainingFile();
+ if (containingFile == null) {
+ return Collections.emptyList();
+ }
+
+ if (AndroidResourceUtil.isRJavaFile(facet, containingFile)) {
+ final Set types = ResourceReferenceConverter.getResourceTypesInCurrentModule(facet);
+ final List result = new ArrayList(types.size());
+
+ for (String resType : types) {
+ final AndroidLightClass resClass = new ResourceTypeClass(facet, resType, aClass);
+ result.add((Psi)resClass);
+ }
+ return result;
+ }
+ else if (AndroidResourceUtil.isManifestJavaFile(facet, containingFile)) {
+ return Arrays.asList((Psi)new PermissionClass(facet, aClass),
+ (Psi)new PermissionGroupClass(facet, aClass));
+ }
+ return Collections.emptyList();
+ }
+}
diff --git a/plugins/android/src/org/jetbrains/android/augment/ManifestInnerClass.java b/plugins/android/src/org/jetbrains/android/augment/ManifestInnerClass.java
new file mode 100644
index 000000000000..fff6efd99239
--- /dev/null
+++ b/plugins/android/src/org/jetbrains/android/augment/ManifestInnerClass.java
@@ -0,0 +1,64 @@
+package org.jetbrains.android.augment;
+
+import com.intellij.openapi.util.Pair;
+import com.intellij.psi.*;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.util.CachedValue;
+import com.intellij.psi.util.CachedValueProvider;
+import com.intellij.psi.util.CachedValuesManager;
+import com.intellij.psi.util.PsiModificationTracker;
+import com.intellij.psi.xml.XmlElement;
+import org.jetbrains.android.dom.manifest.Manifest;
+import org.jetbrains.android.facet.AndroidFacet;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.List;
+
+/**
+* @author Eugene.Kudelevsky
+*/
+abstract class ManifestInnerClass extends AndroidLightClass {
+ private CachedValue myFieldsCache;
+ private final AndroidFacet myFacet;
+
+ ManifestInnerClass(@NotNull AndroidFacet facet, @NotNull String name, @NotNull PsiClass context) {
+ super(context, name);
+ myFacet = facet;
+ }
+
+ @NotNull
+ @Override
+ public PsiField[] getFields() {
+ if (myFieldsCache == null) {
+ myFieldsCache = CachedValuesManager.getManager(getProject()).createCachedValue(new CachedValueProvider() {
+ @Override
+ public Result compute() {
+ final Manifest manifest = myFacet.getManifest();
+ if (manifest == null) {
+ return Result.create(PsiField.EMPTY_ARRAY, PsiModificationTracker.MODIFICATION_COUNT);
+ }
+ final List> pairs = doGetFields(manifest);
+
+ final PsiField[] result = new PsiField[pairs.size()];
+ final PsiClassType stringType = PsiType.getJavaLangString(myManager, GlobalSearchScope.allScope(getProject()));
+ final PsiElementFactory factory = JavaPsiFacade.getElementFactory(getProject());
+ int i = 0;
+ for (Pair pair : pairs) {
+ final AndroidLightField field = new AndroidLightField(pair.getFirst(), ManifestInnerClass.this, stringType);
+ field.setModifiers(PsiModifier.PUBLIC, PsiModifier.STATIC);
+ field.setInitializer(factory.createExpressionFromText("\"" + pair.getSecond() + "\"", field));
+ result[i++] = field;
+ }
+
+ final XmlElement xmlElement = manifest.getXmlElement();
+ final PsiFile psiManifestFile = xmlElement != null ? xmlElement.getContainingFile() : null;
+ return Result.create(result, psiManifestFile != null ? psiManifestFile : PsiModificationTracker.MODIFICATION_COUNT);
+ }
+ });
+ }
+ return myFieldsCache.getValue();
+ }
+
+ @NotNull
+ protected abstract List> doGetFields(@NotNull Manifest manifest);
+}
diff --git a/plugins/android/src/org/jetbrains/android/augment/PermissionClass.java b/plugins/android/src/org/jetbrains/android/augment/PermissionClass.java
new file mode 100644
index 000000000000..4338f7a701cf
--- /dev/null
+++ b/plugins/android/src/org/jetbrains/android/augment/PermissionClass.java
@@ -0,0 +1,41 @@
+package org.jetbrains.android.augment;
+
+import com.intellij.openapi.util.Pair;
+import com.intellij.psi.PsiClass;
+import org.jetbrains.android.dom.manifest.Manifest;
+import org.jetbrains.android.dom.manifest.Permission;
+import org.jetbrains.android.facet.AndroidFacet;
+import org.jetbrains.android.util.AndroidResourceUtil;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+* @author Eugene.Kudelevsky
+*/
+class PermissionClass extends ManifestInnerClass {
+ PermissionClass(@NotNull AndroidFacet facet, @NotNull PsiClass context) {
+ super(facet, "permission", context);
+ }
+
+ @NotNull
+ @Override
+ protected List> doGetFields(@NotNull Manifest manifest) {
+ final List> result = new ArrayList>();
+
+ for (Permission permission : manifest.getPermissions()) {
+ final String name = permission.getName().getValue();
+
+ if (name != null && name.length() > 0) {
+ final int lastDotIndex = name.lastIndexOf('.');
+ final String lastId = name.substring(lastDotIndex + 1);
+
+ if (lastId.length() > 0) {
+ result.add(Pair.create(AndroidResourceUtil.getFieldNameByResourceName(lastId), name));
+ }
+ }
+ }
+ return result;
+ }
+}
diff --git a/plugins/android/src/org/jetbrains/android/augment/PermissionGroupClass.java b/plugins/android/src/org/jetbrains/android/augment/PermissionGroupClass.java
new file mode 100644
index 000000000000..ff90a1899e08
--- /dev/null
+++ b/plugins/android/src/org/jetbrains/android/augment/PermissionGroupClass.java
@@ -0,0 +1,41 @@
+package org.jetbrains.android.augment;
+
+import com.intellij.openapi.util.Pair;
+import com.intellij.psi.PsiClass;
+import org.jetbrains.android.dom.manifest.Manifest;
+import org.jetbrains.android.dom.manifest.PermissionGroup;
+import org.jetbrains.android.facet.AndroidFacet;
+import org.jetbrains.android.util.AndroidResourceUtil;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Eugene.Kudelevsky
+ */
+public class PermissionGroupClass extends ManifestInnerClass {
+ PermissionGroupClass(@NotNull AndroidFacet facet, @NotNull PsiClass context) {
+ super(facet, "permission_group", context);
+ }
+
+ @NotNull
+ @Override
+ protected List> doGetFields(@NotNull Manifest manifest) {
+ final List> result = new ArrayList>();
+
+ for (PermissionGroup permissionGroup : manifest.getPermissionGroups()) {
+ final String name = permissionGroup.getName().getValue();
+
+ if (name != null && name.length() > 0) {
+ final int lastDotIndex = name.lastIndexOf('.');
+ final String lastId = name.substring(lastDotIndex + 1);
+
+ if (lastId.length() > 0) {
+ result.add(Pair.create(AndroidResourceUtil.getFieldNameByResourceName(lastId), name));
+ }
+ }
+ }
+ return result;
+ }
+}
diff --git a/plugins/android/src/org/jetbrains/android/augment/ResourceTypeClass.java b/plugins/android/src/org/jetbrains/android/augment/ResourceTypeClass.java
new file mode 100644
index 000000000000..c6cee4030a2b
--- /dev/null
+++ b/plugins/android/src/org/jetbrains/android/augment/ResourceTypeClass.java
@@ -0,0 +1,57 @@
+package org.jetbrains.android.augment;
+
+import com.intellij.psi.*;
+import com.intellij.psi.util.CachedValue;
+import com.intellij.psi.util.CachedValueProvider;
+import com.intellij.psi.util.CachedValuesManager;
+import com.intellij.psi.util.PsiModificationTracker;
+import org.jetbrains.android.facet.AndroidFacet;
+import org.jetbrains.android.util.AndroidResourceUtil;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.Collection;
+
+/**
+* @author Eugene.Kudelevsky
+*/
+class ResourceTypeClass extends AndroidLightClass {
+ private CachedValue myFieldsCache;
+ private final AndroidFacet myFacet;
+
+ public ResourceTypeClass(@NotNull AndroidFacet facet, @NotNull String name, @NotNull PsiClass context) {
+ super(context, name);
+ myFacet = facet;
+ }
+
+ @NotNull
+ @Override
+ public PsiField[] getFields() {
+ if (myFieldsCache == null) {
+ myFieldsCache = CachedValuesManager.getManager(getProject()).createCachedValue(new CachedValueProvider() {
+ @Override
+ public Result compute() {
+ final PsiField[] fields = buildResourceFields(myFacet, myName, ResourceTypeClass.this);
+ return Result.create(fields, PsiModificationTracker.MODIFICATION_COUNT);
+ }
+ });
+ }
+ return myFieldsCache.getValue();
+ }
+
+ @NotNull
+ private static PsiField[] buildResourceFields(@NotNull AndroidFacet facet,
+ @NotNull String resType,
+ @NotNull final AndroidLightClass context) {
+ final PsiElementFactory factory = JavaPsiFacade.getElementFactory(facet.getModule().getProject());
+ final Collection resNames = facet.getLocalResourceManager().getResourceNames(resType);
+ final PsiField[] result = new PsiField[resNames.size()];
+ int i = 0;
+ for (String resName : resNames) {
+ final AndroidLightField field = new AndroidLightField(AndroidResourceUtil.getFieldNameByResourceName(resName), context, PsiType.INT);
+ field.setModifiers(PsiModifier.PUBLIC, PsiModifier.STATIC);
+ field.setInitializer(factory.createExpressionFromText("0", field));
+ result[i++] = field;
+ }
+ return result;
+ }
+}
diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidAutogenerator.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidAutogenerator.java
index 504790bdc735..3f24d7eaf7a4 100644
--- a/plugins/android/src/org/jetbrains/android/compiler/AndroidAutogenerator.java
+++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidAutogenerator.java
@@ -19,10 +19,8 @@ import com.intellij.openapi.vfs.ReadonlyStatusHandler;
import com.intellij.openapi.vfs.VfsUtilCore;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.search.FilenameIndex;
-import com.intellij.util.ArrayUtil;
import com.intellij.util.containers.HashMap;
import com.intellij.util.containers.HashSet;
-import org.jetbrains.android.compiler.tools.AndroidApt;
import org.jetbrains.android.compiler.tools.AndroidIdl;
import org.jetbrains.android.compiler.tools.AndroidRenderscript;
import org.jetbrains.android.dom.manifest.Manifest;
@@ -33,12 +31,13 @@ import org.jetbrains.android.fileTypes.AndroidRenderscriptFileType;
import org.jetbrains.android.sdk.AndroidPlatform;
import org.jetbrains.android.util.AndroidBundle;
import org.jetbrains.android.util.AndroidCommonUtils;
-import org.jetbrains.android.util.AndroidCompilerMessageKind;
import org.jetbrains.android.util.AndroidUtils;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
+import java.io.BufferedWriter;
import java.io.File;
+import java.io.FileWriter;
import java.io.IOException;
import java.util.*;
@@ -283,36 +282,33 @@ public class AndroidAutogenerator {
// Aapt generation can be very long, so we generate it in temp directory first
tempOutDir = FileUtil.createTempDirectory("android_apt_autogeneration", "tmp");
- final Map> messages =
- AndroidApt.compile(item.myTarget, item.myPlatformToolsRevision, item.myManifestFileOsPath, item.myPackage,
- tempOutDir.getPath(), item.myResDirOsPaths, ArrayUtil.EMPTY_STRING_ARRAY, item.myNonConstantFields);
+ generateStubClasses(item.myPackage, tempOutDir,
+ AndroidUtils.R_CLASS_NAME,
+ AndroidUtils.MANIFEST_CLASS_NAME);
- if (messages.get(AndroidCompilerMessageKind.ERROR).size() == 0) {
- for (String genFileRelPath : item.myGenFileRelPath2package.keySet()) {
- final File srcFile = new File(tempOutDir.getPath() + '/' + genFileRelPath);
+ for (String genFileRelPath : item.myGenFileRelPath2package.keySet()) {
+ final File srcFile = new File(tempOutDir.getPath() + '/' + genFileRelPath);
- if (srcFile.isFile()) {
- final File dstFile = new File(item.myOutputDirOsPath + '/' + genFileRelPath);
+ if (srcFile.isFile()) {
+ final File dstFile = new File(item.myOutputDirOsPath + '/' + genFileRelPath);
- if (dstFile.exists()) {
- if (!FileUtil.delete(dstFile)) {
- ApplicationManager.getApplication().runReadAction(new Runnable() {
- @Override
- public void run() {
- if (module.isDisposed() || module.getProject().isDisposed()) {
- return;
- }
- context.addMessage(CompilerMessageCategory.ERROR,
- "Cannot delete " + FileUtil.toSystemDependentName(dstFile.getPath()), null, -1, -1);
+ if (dstFile.exists()) {
+ if (!FileUtil.delete(dstFile)) {
+ ApplicationManager.getApplication().runReadAction(new Runnable() {
+ @Override
+ public void run() {
+ if (module.isDisposed() || module.getProject().isDisposed()) {
+ return;
}
- });
- }
+ context.addMessage(CompilerMessageCategory.ERROR,
+ "Cannot delete " + FileUtil.toSystemDependentName(dstFile.getPath()), null, -1, -1);
+ }
+ });
}
- FileUtil.rename(srcFile, dstFile);
}
+ FileUtil.rename(srcFile, dstFile);
}
}
- AndroidCompileUtil.addMessages(context, AndroidCompileUtil.toCompilerMessageCategoryKeys(messages), module);
for (Map.Entry entry : item.myGenFileRelPath2package.entrySet()) {
final String path = item.myOutputDirOsPath + '/' + entry.getKey();
@@ -328,16 +324,13 @@ public class AndroidAutogenerator {
if (genSourceRoot != null) {
genSourceRoot.refresh(false, true);
}
+ facet.clearAutogeneratedFiles(AndroidAutogeneratorMode.AAPT);
- if (messages.get(AndroidCompilerMessageKind.ERROR).size() == 0) {
- facet.clearAutogeneratedFiles(AndroidAutogeneratorMode.AAPT);
+ for (String relPath : item.myGenFileRelPath2package.keySet()) {
+ final VirtualFile genFile = LocalFileSystem.getInstance().findFileByPath(item.myOutputDirOsPath + '/' + relPath);
- for (String relPath : item.myGenFileRelPath2package.keySet()) {
- final VirtualFile genFile = LocalFileSystem.getInstance().findFileByPath(item.myOutputDirOsPath + '/' + relPath);
-
- if (genFile != null && genFile.exists()) {
- facet.markFileAutogenerated(AndroidAutogeneratorMode.AAPT, genFile);
- }
+ if (genFile != null && genFile.exists()) {
+ facet.markFileAutogenerated(AndroidAutogeneratorMode.AAPT, genFile);
}
}
}
@@ -357,6 +350,30 @@ public class AndroidAutogenerator {
}
}
+ private static void generateStubClasses(@NotNull String aPackage, @NotNull File outputDir, @NotNull String... classNames)
+ throws IOException {
+ assert aPackage.length() > 0;
+
+ for (String className : classNames) {
+ final File packageDir = new File(outputDir.getPath() + '/' + aPackage.replace('.', '/'));
+ if (!packageDir.exists() && !packageDir.mkdirs()) {
+ throw new IOException("Cannot create directory " + FileUtil.toSystemDependentName(packageDir.getPath()));
+ }
+ final BufferedWriter writer = new BufferedWriter(new FileWriter(new File(packageDir, className + ".java")));
+ try {
+ writer.write(
+ "package " + aPackage + ";\n\n" +
+ "/* This stub is for using by IDE only. It is NOT the " + className + " class actually packed into APK */\n" +
+ "public final class " + className + " {\n" +
+ "}"
+ );
+ }
+ finally {
+ writer.close();
+ }
+ }
+ }
+
private static void removeAllFilesWithSameName(@NotNull final Module module, @NotNull File file, @NotNull String directoryPath) {
final VirtualFile vFile = LocalFileSystem.getInstance().findFileByIoFile(file);
final VirtualFile genDir = LocalFileSystem.getInstance().findFileByPath(directoryPath);
diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java
index 37869ef757d1..b31a35ad3cf7 100644
--- a/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java
+++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidCompileUtil.java
@@ -15,7 +15,6 @@
*/
package org.jetbrains.android.compiler;
-import com.android.resources.ResourceType;
import com.intellij.CommonBundle;
import com.intellij.compiler.CompilerConfiguration;
import com.intellij.compiler.CompilerConfigurationImpl;
@@ -35,7 +34,6 @@ import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleManager;
import com.intellij.openapi.module.ModuleUtil;
-import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.*;
import com.intellij.openapi.ui.Messages;
@@ -57,18 +55,16 @@ import com.intellij.util.containers.HashMap;
import com.intellij.util.containers.HashSet;
import org.jetbrains.android.compiler.artifact.*;
import org.jetbrains.android.dom.manifest.Manifest;
-import org.jetbrains.android.dom.resources.Attr;
-import org.jetbrains.android.dom.resources.DeclareStyleable;
-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.AndroidFacetConfiguration;
import org.jetbrains.android.facet.AndroidRootUtil;
import org.jetbrains.android.fileTypes.AndroidIdlFileType;
import org.jetbrains.android.fileTypes.AndroidRenderscriptFileType;
-import org.jetbrains.android.resourceManagers.LocalResourceManager;
import org.jetbrains.android.sdk.AndroidPlatform;
-import org.jetbrains.android.util.*;
+import org.jetbrains.android.util.AndroidCommonUtils;
+import org.jetbrains.android.util.AndroidCompilerMessageKind;
+import org.jetbrains.android.util.AndroidExecutionUtil;
+import org.jetbrains.android.util.AndroidUtils;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -140,18 +136,6 @@ public class AndroidCompileUtil {
addMessages(context, messages, null, module);
}
- public static void addMessages(@NotNull Map> messages,
- @NotNull Map> toAdd) {
- for (Map.Entry> entry : toAdd.entrySet()) {
- List list = messages.get(entry.getKey());
- if (list == null) {
- list = new ArrayList();
- messages.put(entry.getKey(), list);
- }
- list.addAll(entry.getValue());
- }
- }
-
static void addMessages(final CompileContext context,
final Map> messages,
@Nullable final Map presentableFilesMap,
@@ -711,95 +695,6 @@ public class AndroidCompileUtil {
}
}
- public static void collectAllResources(@NotNull final AndroidFacet facet, final Set resourceSet) {
- final LocalResourceManager manager = facet.getLocalResourceManager();
- final Project project = facet.getModule().getProject();
-
- for (final ResourceType resType : AndroidResourceUtil.VALUE_RESOURCE_TYPES) {
- for (final ResourceElement element : manager.getValueResources(resType.getName())) {
- waitForSmartMode(project);
-
- ApplicationManager.getApplication().runReadAction(new Runnable() {
- @Override
- public void run() {
- if (!element.isValid() || facet.getModule().isDisposed() || project.isDisposed()) {
- return;
- }
- final String name = element.getName().getValue();
-
- if (name != null) {
- resourceSet.add(new ResourceEntry(resType.getName(), name));
- }
- }
- });
- }
- }
-
- for (final Pair pair : manager.getResourceElements()) {
- final Resources resources = pair.getFirst();
- waitForSmartMode(project);
-
- ApplicationManager.getApplication().runReadAction(new Runnable() {
- @Override
- public void run() {
- if (!resources.isValid() || facet.getModule().isDisposed() || project.isDisposed()) {
- return;
- }
-
- for (final Attr attr : resources.getAttrs()) {
- final String name = attr.getName().getValue();
-
- if (name != null) {
- resourceSet.add(new ResourceEntry(ResourceType.ATTR.getName(), name));
- }
- }
-
- for (final DeclareStyleable styleable : resources.getDeclareStyleables()) {
- final String name = styleable.getName().getValue();
-
- if (name != null) {
- resourceSet.add(new ResourceEntry(ResourceType.DECLARE_STYLEABLE.getName(), name));
- }
- }
- }
- });
- }
-
- waitForSmartMode(project);
-
- ApplicationManager.getApplication().runReadAction(new Runnable() {
- @Override
- public void run() {
- if (facet.getModule().isDisposed() || project.isDisposed()) {
- return;
- }
-
- for (String id : manager.getIds()) {
- resourceSet.add(new ResourceEntry(ResourceType.ID.getName(), id));
- }
- }
- });
- final HashSet visited = new HashSet();
-
- for (VirtualFile subdir : manager.getResourceSubdirs(null)) {
- final HashSet resourceFiles = new HashSet();
- AndroidUtils.collectFiles(subdir, visited, resourceFiles);
-
- for (VirtualFile file : resourceFiles) {
- final String subdirName = subdir.getName();
- final int index = subdirName.indexOf('-');
- final String type = index >= 0 ? subdirName.substring(0, index) : subdirName;
- resourceSet.add(new ResourceEntry(type, FileUtil.getNameWithoutExtension(file.getName())));
- }
- }
- }
-
- private static void waitForSmartMode(Project project) {
- if (!ApplicationManager.getApplication().isReadAccessAllowed()) {
- DumbService.getInstance(project).waitForSmartMode();
- }
- }
-
@NotNull
public static String[] toOsPaths(@NotNull VirtualFile[] classFilesDirs) {
final String[] classFilesDirOsPaths = new String[classFilesDirs.length];
diff --git a/plugins/android/src/org/jetbrains/android/dom/converters/ResourceReferenceConverter.java b/plugins/android/src/org/jetbrains/android/dom/converters/ResourceReferenceConverter.java
index af899538c7a6..a49a159a0e39 100644
--- a/plugins/android/src/org/jetbrains/android/dom/converters/ResourceReferenceConverter.java
+++ b/plugins/android/src/org/jetbrains/android/dom/converters/ResourceReferenceConverter.java
@@ -160,7 +160,7 @@ public class ResourceReferenceConverter extends ResolvingConverter getResourceTypesInCurrentModule(@NotNull AndroidFacet facet) {
+ public static Set getResourceTypesInCurrentModule(@NotNull AndroidFacet facet) {
final Set result = new HashSet();
final LocalResourceManager manager = facet.getLocalResourceManager();
@@ -173,6 +173,9 @@ public class ResourceReferenceConverter extends ResolvingConverter 0) {
+ result.add(ResourceType.ID.getName());
+ }
return result;
}
@@ -205,17 +208,10 @@ public class ResourceReferenceConverter extends ResolvingConverter result,
boolean explicitResourceType) {
- ResourceManager manager = facet.getResourceManager(resPackage);
- if (manager == null) return;
- for (String name : manager.getValueResourceNames(type)) {
- result.add(referenceTo(type, resPackage, name, explicitResourceType));
- }
- for (String file : manager.getFileResourcesNames(type)) {
- result.add(referenceTo(type, resPackage, file, explicitResourceType));
- }
- if (type.equals("id")) {
- for (String id : manager.getIds()) {
- result.add(referenceTo(type, resPackage, id, explicitResourceType));
+ final ResourceManager manager = facet.getResourceManager(resPackage);
+ if (manager != null) {
+ for (String name : manager.getResourceNames(type)) {
+ result.add(referenceTo(type, resPackage, name, explicitResourceType));
}
}
}
diff --git a/plugins/android/src/org/jetbrains/android/facet/AndroidFacet.java b/plugins/android/src/org/jetbrains/android/facet/AndroidFacet.java
index 813a3d6592f8..89f99681da8e 100644
--- a/plugins/android/src/org/jetbrains/android/facet/AndroidFacet.java
+++ b/plugins/android/src/org/jetbrains/android/facet/AndroidFacet.java
@@ -40,7 +40,6 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtil;
-import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.IndexNotReadyException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.projectRoots.Sdk;
@@ -87,7 +86,6 @@ import org.jetbrains.android.sdk.*;
import org.jetbrains.android.util.AndroidBundle;
import org.jetbrains.android.util.AndroidCommonUtils;
import org.jetbrains.android.util.AndroidUtils;
-import org.jetbrains.android.util.ResourceEntry;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -446,12 +444,6 @@ public class AndroidFacet extends Facet {
return;
}
- DumbService.getInstance(project).waitForSmartMode();
-
- final HashSet resourceSet = new HashSet();
- AndroidCompileUtil.collectAllResources(AndroidFacet.this, resourceSet);
- myListener.setResourceSet(resourceSet);
-
if (AndroidAptCompiler.isToCompileModule(module, getConfiguration())) {
AndroidCompileUtil.generate(module, AndroidAutogeneratorMode.AAPT);
}
diff --git a/plugins/android/src/org/jetbrains/android/facet/AndroidFacetEditorTab.java b/plugins/android/src/org/jetbrains/android/facet/AndroidFacetEditorTab.java
index 10d4fde3fc36..ce5b2d4f178c 100644
--- a/plugins/android/src/org/jetbrains/android/facet/AndroidFacetEditorTab.java
+++ b/plugins/android/src/org/jetbrains/android/facet/AndroidFacetEditorTab.java
@@ -422,10 +422,6 @@ public class AndroidFacetEditorTab extends FacetEditorTab {
String absLibsPath = myNativeLibsFolder.getText().trim();
myConfiguration.LIBS_FOLDER_RELATIVE_PATH = absLibsPath.length() > 0 ? '/' + getAndCheckRelativePath(absLibsPath, false) : "";
- if (myConfiguration.LIBRARY_PROJECT != myIsLibraryProjectCheckbox.isSelected()) {
- runApt = true;
- }
-
myConfiguration.CUSTOM_DEBUG_KEYSTORE_PATH = getSelectedCustomKeystorePath();
myConfiguration.LIBRARY_PROJECT = myIsLibraryProjectCheckbox.isSelected();
@@ -454,9 +450,6 @@ public class AndroidFacetEditorTab extends FacetEditorTab {
boolean useCustomAptSrc = myUseCustomSourceDirectoryRadio.isSelected();
- if (myConfiguration.USE_CUSTOM_APK_RESOURCE_FOLDER != useCustomAptSrc) {
- runApt = true;
- }
myConfiguration.USE_CUSTOM_APK_RESOURCE_FOLDER = useCustomAptSrc;
String absAptSourcePath = myCustomAptSourceDirField.getText().trim();
@@ -464,11 +457,7 @@ public class AndroidFacetEditorTab extends FacetEditorTab {
if (absAptSourcePath.length() == 0) {
throw new ConfigurationException("Resources folder not specified");
}
- String newCustomAptSourceFolder = '/' + getAndCheckRelativePath(absAptSourcePath, false);
- if (!newCustomAptSourceFolder.equals(myConfiguration.CUSTOM_APK_RESOURCE_FOLDER)) {
- runApt = true;
- }
- myConfiguration.CUSTOM_APK_RESOURCE_FOLDER = newCustomAptSourceFolder;
+ myConfiguration.CUSTOM_APK_RESOURCE_FOLDER = '/' + getAndCheckRelativePath(absAptSourcePath, false);
}
else {
String relPath = toRelativePath(absAptSourcePath);
diff --git a/plugins/android/src/org/jetbrains/android/facet/AndroidResourceFilesListener.java b/plugins/android/src/org/jetbrains/android/facet/AndroidResourceFilesListener.java
index 40f84fa2a1e0..d356350f68e3 100644
--- a/plugins/android/src/org/jetbrains/android/facet/AndroidResourceFilesListener.java
+++ b/plugins/android/src/org/jetbrains/android/facet/AndroidResourceFilesListener.java
@@ -20,11 +20,9 @@ import com.android.resources.ResourceFolderType;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.module.Module;
import com.intellij.openapi.module.ModuleUtil;
-import com.intellij.openapi.project.DumbService;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Computable;
import com.intellij.openapi.vfs.*;
-import com.intellij.util.containers.HashSet;
import com.intellij.util.ui.update.MergingUpdateQueue;
import com.intellij.util.ui.update.Update;
import org.jetbrains.android.compiler.AndroidAptCompiler;
@@ -35,14 +33,12 @@ import org.jetbrains.android.fileTypes.AndroidIdlFileType;
import org.jetbrains.android.fileTypes.AndroidRenderscriptFileType;
import org.jetbrains.android.util.AndroidCommonUtils;
import org.jetbrains.android.util.AndroidUtils;
-import org.jetbrains.android.util.ResourceEntry;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
-import java.util.Set;
import static org.jetbrains.android.util.AndroidUtils.findSourceRoot;
@@ -59,9 +55,6 @@ class AndroidResourceFilesListener extends VirtualFileAdapter {
private final AndroidFacet myFacet;
private String myCachedPackage = null;
- private volatile Set myResourceSet = new HashSet();
- private static final Object RESOURCES_SET_LOCK = new Object();
-
public AndroidResourceFilesListener(final AndroidFacet facet) {
myFacet = facet;
myQueue = new MergingUpdateQueue("AndroidResourcesCompilationQueue", 300, true, null, myFacet, null, false);
@@ -128,12 +121,6 @@ class AndroidResourceFilesListener extends VirtualFileAdapter {
}
}
- public void setResourceSet(@NotNull Set resourceSet) {
- synchronized (RESOURCES_SET_LOCK) {
- myResourceSet = resourceSet;
- }
- }
-
private class MyUpdate extends Update {
private final VirtualFileEvent myEvent;
@@ -160,23 +147,6 @@ class AndroidResourceFilesListener extends VirtualFileAdapter {
}
for (AndroidAutogeneratorMode autogenerationMode : autogenerationModes) {
- if (autogenerationMode == AndroidAutogeneratorMode.AAPT &&
- AndroidRootUtil.getManifestFile(myFacet) != myEvent.getFile()) {
-
- final HashSet resourceSet = new HashSet();
-
- DumbService.getInstance(myFacet.getModule().getProject()).waitForSmartMode();
-
- AndroidCompileUtil.collectAllResources(myFacet, resourceSet);
-
- synchronized (RESOURCES_SET_LOCK) {
- if (resourceSet.equals(myResourceSet) &&
- !myFacet.areSourcesGeneratedWithErrors(AndroidAutogeneratorMode.AAPT)) {
- return;
- }
- myResourceSet = resourceSet;
- }
- }
AndroidCompileUtil.generate(myFacet.getModule(), autogenerationMode, true);
}
}
@@ -216,7 +186,7 @@ class AndroidResourceFilesListener extends VirtualFileAdapter {
final List modes = new ArrayList();
- if (AndroidAptCompiler.isToCompileModule(module, myFacet.getConfiguration()) && (gp == resourceDir || manifestFile == file)) {
+ if (AndroidAptCompiler.isToCompileModule(module, myFacet.getConfiguration()) && manifestFile == file) {
final Manifest manifest = myFacet.getManifest();
final String aPackage = manifest != null ? manifest.getPackage().getValue() : null;
diff --git a/plugins/android/src/org/jetbrains/android/resourceManagers/ResourceManager.java b/plugins/android/src/org/jetbrains/android/resourceManagers/ResourceManager.java
index 4615664addd9..98feb277c883 100644
--- a/plugins/android/src/org/jetbrains/android/resourceManagers/ResourceManager.java
+++ b/plugins/android/src/org/jetbrains/android/resourceManagers/ResourceManager.java
@@ -262,6 +262,17 @@ public abstract class ResourceManager {
return result;
}
+ @NotNull
+ public Collection getResourceNames(@NotNull String type) {
+ final Set result = new HashSet();
+ result.addAll(getValueResourceNames(type));
+ result.addAll(getFileResourcesNames(type));
+ if (type.equals("id")) {
+ result.addAll(getIds());
+ }
+ return result;
+ }
+
@Nullable
public abstract AttributeDefinitions getAttributeDefinitions();
diff --git a/plugins/android/src/org/jetbrains/android/util/AndroidResourceUtil.java b/plugins/android/src/org/jetbrains/android/util/AndroidResourceUtil.java
index 0fdc4a277520..28976d7b4312 100644
--- a/plugins/android/src/org/jetbrains/android/util/AndroidResourceUtil.java
+++ b/plugins/android/src/org/jetbrains/android/util/AndroidResourceUtil.java
@@ -572,6 +572,15 @@ public class AndroidResourceUtil {
return false;
}
+ public static boolean isManifestJavaFile(@NotNull AndroidFacet facet, @NotNull PsiFile file) {
+ if (file.getName().equals(AndroidCommonUtils.MANIFEST_JAVA_FILE_NAME) && file instanceof PsiJavaFile) {
+ final Manifest manifest = facet.getManifest();
+ final PsiJavaFile javaFile = (PsiJavaFile)file;
+ return manifest != null && javaFile.getPackageName().equals(manifest.getPackage().getValue());
+ }
+ return false;
+ }
+
public static List getNames(@NotNull Collection resourceTypes) {
if (resourceTypes.size() == 0) {
return Collections.emptyList();
@@ -803,4 +812,9 @@ public class AndroidResourceUtil {
}
return AndroidFileTemplateProvider.RESOURCE_FILE_TEMPLATE;
}
+
+ @NotNull
+ public static String getFieldNameByResourceName(@NotNull String fieldName) {
+ return fieldName.replace('.', '_').replace('-', '_');
+ }
}
diff --git a/plugins/android/src/org/jetbrains/android/util/AndroidUtils.java b/plugins/android/src/org/jetbrains/android/util/AndroidUtils.java
index f486bd8b733c..d901f36fe38d 100644
--- a/plugins/android/src/org/jetbrains/android/util/AndroidUtils.java
+++ b/plugins/android/src/org/jetbrains/android/util/AndroidUtils.java
@@ -109,6 +109,7 @@ public class AndroidUtils {
@NonNls public static final String APPLICATION_CLASS_NAME = "android.app.Application";
@NonNls public static final String ACTIVITY_BASE_CLASS_NAME = "android.app.Activity";
@NonNls public static final String R_CLASS_NAME = "R";
+ @NonNls public static final String MANIFEST_CLASS_NAME = "Manifest";
@NonNls public static final String LAUNCH_ACTION_NAME = "android.intent.action.MAIN";
@NonNls public static final String LAUNCH_CATEGORY_NAME = "android.intent.category.LAUNCHER";
@NonNls public static final String INSTRUMENTATION_RUNNER_BASE_CLASS = "android.app.Instrumentation";
diff --git a/plugins/android/testData/dom/R.java b/plugins/android/testData/dom/R.java
index 8534820abf58..8dd79eb2cd09 100644
--- a/plugins/android/testData/dom/R.java
+++ b/plugins/android/testData/dom/R.java
@@ -1,12 +1,4 @@
package p1.p2;
public final class R {
- public static final class string {
- public static final int welcome=0x7f040001;
- public static final int hello=0x7f040000;
- }
-
- public static final class drawable {
- public static final int picture3=0x7f040002;
- }
}
diff --git a/plugins/android/testData/dom/layout/JavaCompletion1.java b/plugins/android/testData/dom/layout/JavaCompletion1.java
new file mode 100644
index 000000000000..c44d4e3b910f
--- /dev/null
+++ b/plugins/android/testData/dom/layout/JavaCompletion1.java
@@ -0,0 +1,7 @@
+package p1.p2;
+
+public class JavaCompletion {
+ public void f() {
+ R.layo
+ }
+}
\ No newline at end of file
diff --git a/plugins/android/testData/dom/layout/JavaCompletion1_after.java b/plugins/android/testData/dom/layout/JavaCompletion1_after.java
new file mode 100644
index 000000000000..02f5932e2e53
--- /dev/null
+++ b/plugins/android/testData/dom/layout/JavaCompletion1_after.java
@@ -0,0 +1,7 @@
+package p1.p2;
+
+public class JavaCompletion {
+ public void f() {
+ R.layout
+ }
+}
\ No newline at end of file
diff --git a/plugins/android/testData/dom/layout/JavaCompletion2.java b/plugins/android/testData/dom/layout/JavaCompletion2.java
new file mode 100644
index 000000000000..da1295f7eb9b
--- /dev/null
+++ b/plugins/android/testData/dom/layout/JavaCompletion2.java
@@ -0,0 +1,7 @@
+package p1.p2;
+
+public class JavaCompletion {
+ public void f() {
+ R.layout.mai
+ }
+}
\ No newline at end of file
diff --git a/plugins/android/testData/dom/layout/JavaCompletion2_after.java b/plugins/android/testData/dom/layout/JavaCompletion2_after.java
new file mode 100644
index 000000000000..eaa8a6ef0ca0
--- /dev/null
+++ b/plugins/android/testData/dom/layout/JavaCompletion2_after.java
@@ -0,0 +1,7 @@
+package p1.p2;
+
+public class JavaCompletion {
+ public void f() {
+ R.layout.main
+ }
+}
\ No newline at end of file
diff --git a/plugins/android/testData/dom/layout/JavaCompletion3.java b/plugins/android/testData/dom/layout/JavaCompletion3.java
new file mode 100644
index 000000000000..f91454d35e1c
--- /dev/null
+++ b/plugins/android/testData/dom/layout/JavaCompletion3.java
@@ -0,0 +1,7 @@
+package p1.p2;
+
+public class JavaCompletion {
+ public void f() {
+ R.xm
+ }
+}
\ No newline at end of file
diff --git a/plugins/android/testData/dom/layout/JavaCompletion3_after.java b/plugins/android/testData/dom/layout/JavaCompletion3_after.java
new file mode 100644
index 000000000000..1e3b67ae88a3
--- /dev/null
+++ b/plugins/android/testData/dom/layout/JavaCompletion3_after.java
@@ -0,0 +1,7 @@
+package p1.p2;
+
+public class JavaCompletion {
+ public void f() {
+ R.xm
+ }
+}
\ No newline at end of file
diff --git a/plugins/android/testData/dom/layout/JavaHighlighting1.java b/plugins/android/testData/dom/layout/JavaHighlighting1.java
new file mode 100644
index 000000000000..85e118f5e804
--- /dev/null
+++ b/plugins/android/testData/dom/layout/JavaHighlighting1.java
@@ -0,0 +1,7 @@
+package p1.p2;
+
+public class JavaHighlighting1 {
+ public void f() {
+ int n = R.xml.main;
+ }
+}
\ No newline at end of file
diff --git a/plugins/android/testData/dom/layout/JavaHighlighting2.java b/plugins/android/testData/dom/layout/JavaHighlighting2.java
new file mode 100644
index 000000000000..47b9e01b1f5d
--- /dev/null
+++ b/plugins/android/testData/dom/layout/JavaHighlighting2.java
@@ -0,0 +1,7 @@
+package p1;
+
+public class JavaHighlighting6 {
+ public void f() {
+ int n = p1.p2.R.layout.main;
+ }
+}
\ No newline at end of file
diff --git a/plugins/android/testData/dom/layout/JavaHighlighting3.java b/plugins/android/testData/dom/layout/JavaHighlighting3.java
new file mode 100644
index 000000000000..499eda30888f
--- /dev/null
+++ b/plugins/android/testData/dom/layout/JavaHighlighting3.java
@@ -0,0 +1,7 @@
+package p1.p2;
+
+public class JavaHighlighting3 {
+ public void f() {
+ int n = R.layout.unknown;
+ }
+}
\ No newline at end of file
diff --git a/plugins/android/testData/dom/layout/JavaHighlighting4.java b/plugins/android/testData/dom/layout/JavaHighlighting4.java
new file mode 100644
index 000000000000..66806e9ab4b1
--- /dev/null
+++ b/plugins/android/testData/dom/layout/JavaHighlighting4.java
@@ -0,0 +1,7 @@
+package p1.p2;
+
+public class JavaHighlighting4 {
+ public void f() {
+ int n = R.layout.main;
+ }
+}
\ No newline at end of file
diff --git a/plugins/android/testData/dom/layout/JavaHighlighting5.java b/plugins/android/testData/dom/layout/JavaHighlighting5.java
new file mode 100644
index 000000000000..25387aced362
--- /dev/null
+++ b/plugins/android/testData/dom/layout/JavaHighlighting5.java
@@ -0,0 +1,7 @@
+package p1;
+
+public class JavaHighlighting5 {
+ public void f() {
+ int n = R.layout.main;
+ }
+}
\ No newline at end of file
diff --git a/plugins/android/testData/dom/layout/JavaIdCompletion.java b/plugins/android/testData/dom/layout/JavaIdCompletion.java
new file mode 100644
index 000000000000..77771a1b1280
--- /dev/null
+++ b/plugins/android/testData/dom/layout/JavaIdCompletion.java
@@ -0,0 +1,7 @@
+package p1.p2;
+
+public class JavaIdCompletion {
+ public void f() {
+ int n = R.id.myComp;
+ }
+}
\ No newline at end of file
diff --git a/plugins/android/testData/dom/layout/JavaIdCompletion_after.java b/plugins/android/testData/dom/layout/JavaIdCompletion_after.java
new file mode 100644
index 000000000000..ac6b96173d27
--- /dev/null
+++ b/plugins/android/testData/dom/layout/JavaIdCompletion_after.java
@@ -0,0 +1,7 @@
+package p1.p2;
+
+public class JavaIdCompletion {
+ public void f() {
+ int n = R.id.myComponent;
+ }
+}
\ No newline at end of file
diff --git a/plugins/android/testData/dom/layout/main.xml b/plugins/android/testData/dom/layout/main.xml
new file mode 100644
index 000000000000..67acba66b044
--- /dev/null
+++ b/plugins/android/testData/dom/layout/main.xml
@@ -0,0 +1,3 @@
+
+
+
\ No newline at end of file
diff --git a/plugins/android/testData/dom/manifest/JavaHighlighting.java b/plugins/android/testData/dom/manifest/JavaHighlighting.java
new file mode 100644
index 000000000000..bcfb4435c5cb
--- /dev/null
+++ b/plugins/android/testData/dom/manifest/JavaHighlighting.java
@@ -0,0 +1,17 @@
+package p1.p2;
+
+import java.lang.String;
+
+public class JavaCompletion {
+ public void f() {
+ String s = Manifest.permission.perm1;
+ s = Manifest.permission.perm2;
+ s = Manifest.permission.unknown;
+ s = Manifest.permissio.perm1;
+ s = Manifest.permission.aba_perm;
+
+ s = Manifest.permission_group.group1;
+ s = Manifest.permission_group.unknown;
+ s = Manifest.permission_group.aba_group;
+ }
+}
\ No newline at end of file
diff --git a/plugins/android/testData/dom/manifest/Manifest.java b/plugins/android/testData/dom/manifest/Manifest.java
new file mode 100644
index 000000000000..078d765f9d84
--- /dev/null
+++ b/plugins/android/testData/dom/manifest/Manifest.java
@@ -0,0 +1,4 @@
+package p1.p2;
+
+public class Manifest {
+}
\ No newline at end of file
diff --git a/plugins/android/testData/dom/manifest/PermissionsManifest.xml b/plugins/android/testData/dom/manifest/PermissionsManifest.xml
new file mode 100644
index 000000000000..9fc3251d9696
--- /dev/null
+++ b/plugins/android/testData/dom/manifest/PermissionsManifest.xml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
diff --git a/plugins/android/testData/dom/resources/JavaCompletion1.java b/plugins/android/testData/dom/resources/JavaCompletion1.java
new file mode 100644
index 000000000000..f3d0e6365705
--- /dev/null
+++ b/plugins/android/testData/dom/resources/JavaCompletion1.java
@@ -0,0 +1,7 @@
+package p1.p2;
+
+public class JavaCompletion1 {
+ public void f() {
+ int n = R.string.my_str;
+ }
+}
\ No newline at end of file
diff --git a/plugins/android/testData/dom/resources/JavaCompletion1_after.java b/plugins/android/testData/dom/resources/JavaCompletion1_after.java
new file mode 100644
index 000000000000..3baca951ac29
--- /dev/null
+++ b/plugins/android/testData/dom/resources/JavaCompletion1_after.java
@@ -0,0 +1,7 @@
+package p1.p2;
+
+public class JavaCompletion1 {
+ public void f() {
+ int n = R.string.my_string;
+ }
+}
\ No newline at end of file
diff --git a/plugins/android/testData/dom/resources/JavaCompletion2.java b/plugins/android/testData/dom/resources/JavaCompletion2.java
new file mode 100644
index 000000000000..d3905fc1a8c7
--- /dev/null
+++ b/plugins/android/testData/dom/resources/JavaCompletion2.java
@@ -0,0 +1,7 @@
+package p1.p2;
+
+public class JavaCompletion1 {
+ public void f() {
+ int n = R.stri;
+ }
+}
\ No newline at end of file
diff --git a/plugins/android/testData/dom/resources/JavaCompletion2_after.java b/plugins/android/testData/dom/resources/JavaCompletion2_after.java
new file mode 100644
index 000000000000..b8dc9bd578d7
--- /dev/null
+++ b/plugins/android/testData/dom/resources/JavaCompletion2_after.java
@@ -0,0 +1,7 @@
+package p1.p2;
+
+public class JavaCompletion1 {
+ public void f() {
+ int n = R.string;
+ }
+}
\ No newline at end of file
diff --git a/plugins/android/testData/dom/resources/JavaCompletion3.java b/plugins/android/testData/dom/resources/JavaCompletion3.java
new file mode 100644
index 000000000000..2be43c4890bb
--- /dev/null
+++ b/plugins/android/testData/dom/resources/JavaCompletion3.java
@@ -0,0 +1,7 @@
+package p1.p2;
+
+public class JavaCompletion1 {
+ public void f() {
+ int n = R.string.unknow;
+ }
+}
\ No newline at end of file
diff --git a/plugins/android/testData/dom/resources/JavaCompletion3_after.java b/plugins/android/testData/dom/resources/JavaCompletion3_after.java
new file mode 100644
index 000000000000..e1db3724d1dc
--- /dev/null
+++ b/plugins/android/testData/dom/resources/JavaCompletion3_after.java
@@ -0,0 +1,7 @@
+package p1.p2;
+
+public class JavaCompletion1 {
+ public void f() {
+ int n = R.string.unknow;
+ }
+}
\ No newline at end of file
diff --git a/plugins/android/testData/dom/resources/JavaCompletion4.java b/plugins/android/testData/dom/resources/JavaCompletion4.java
new file mode 100644
index 000000000000..cc723f5d48fb
--- /dev/null
+++ b/plugins/android/testData/dom/resources/JavaCompletion4.java
@@ -0,0 +1,7 @@
+package p1.p2;
+
+public class JavaCompletion1 {
+ public void f() {
+ int n = R.style.Theme_My;
+ }
+}
\ No newline at end of file
diff --git a/plugins/android/testData/dom/resources/JavaCompletion4_after.java b/plugins/android/testData/dom/resources/JavaCompletion4_after.java
new file mode 100644
index 000000000000..b85158e6ceb1
--- /dev/null
+++ b/plugins/android/testData/dom/resources/JavaCompletion4_after.java
@@ -0,0 +1,7 @@
+package p1.p2;
+
+public class JavaCompletion1 {
+ public void f() {
+ int n = R.style.Theme_MyCustomStyle
+ }
+}
\ No newline at end of file
diff --git a/plugins/android/testData/dom/resources/JavaHighlighting1.java b/plugins/android/testData/dom/resources/JavaHighlighting1.java
new file mode 100644
index 000000000000..3baca951ac29
--- /dev/null
+++ b/plugins/android/testData/dom/resources/JavaHighlighting1.java
@@ -0,0 +1,7 @@
+package p1.p2;
+
+public class JavaCompletion1 {
+ public void f() {
+ int n = R.string.my_string;
+ }
+}
\ No newline at end of file
diff --git a/plugins/android/testData/dom/resources/JavaHighlighting2.java b/plugins/android/testData/dom/resources/JavaHighlighting2.java
new file mode 100644
index 000000000000..8b14d351ca08
--- /dev/null
+++ b/plugins/android/testData/dom/resources/JavaHighlighting2.java
@@ -0,0 +1,7 @@
+package p1.p2;
+
+public class JavaCompletion1 {
+ public void f() {
+ int n = R.string.unknown;
+ }
+}
\ No newline at end of file
diff --git a/plugins/android/testData/dom/resources/value_resources.xml b/plugins/android/testData/dom/resources/value_resources.xml
new file mode 100644
index 000000000000..785906d52e3e
--- /dev/null
+++ b/plugins/android/testData/dom/resources/value_resources.xml
@@ -0,0 +1,4 @@
+
+ abacaba
+
+
\ No newline at end of file
diff --git a/plugins/android/testSrc/org/jetbrains/android/dom/AndroidDomTest.java b/plugins/android/testSrc/org/jetbrains/android/dom/AndroidDomTest.java
index a924b65a8d4b..ac05b5376693 100644
--- a/plugins/android/testSrc/org/jetbrains/android/dom/AndroidDomTest.java
+++ b/plugins/android/testSrc/org/jetbrains/android/dom/AndroidDomTest.java
@@ -39,6 +39,14 @@ abstract class AndroidDomTest extends AndroidTestCase {
return "dom/res";
}
+ protected void doTestJavaCompletion(String aPackage) throws Throwable {
+ final String fileName = getTestName(false) + ".java";
+ final VirtualFile file = copyFileToProject(fileName, "src/" + aPackage.replace('/', '.') + '/' + fileName);
+ myFixture.configureFromExistingVirtualFile(file);
+ myFixture.complete(CompletionType.BASIC);
+ myFixture.checkResultByFile(testFolder + '/' + getTestName(false) + "_after.java");
+ }
+
protected static String[] withNamespace(String... arr) {
List list = new ArrayList();
for (String s : arr) {
@@ -66,6 +74,13 @@ abstract class AndroidDomTest extends AndroidTestCase {
myFixture.checkHighlighting(true, false, false);
}
+ protected void doTestJavaHighlighting(String aPackage) throws Throwable {
+ final String fileName = getTestName(false) + ".java";
+ final VirtualFile virtualFile = copyFileToProject(fileName, "src/" + aPackage.replace('.', '/') + '/' + fileName);
+ myFixture.configureFromExistingVirtualFile(virtualFile);
+ myFixture.checkHighlighting(true, false, false);
+ }
+
protected void doTestCompletion() throws Throwable {
doTestCompletion(true);
}
diff --git a/plugins/android/testSrc/org/jetbrains/android/dom/AndroidLayoutDomTest.java b/plugins/android/testSrc/org/jetbrains/android/dom/AndroidLayoutDomTest.java
index d859ac793252..d43a2bef3d54 100644
--- a/plugins/android/testSrc/org/jetbrains/android/dom/AndroidLayoutDomTest.java
+++ b/plugins/android/testSrc/org/jetbrains/android/dom/AndroidLayoutDomTest.java
@@ -385,5 +385,50 @@ public class AndroidLayoutDomTest extends AndroidDomTest {
copyFileToProject("OnClick_Class3.java", "src/p1/p2/OnClick_Class3.java");
copyFileToProject("OnClick_Class4.java", "src/p1/p2/OnClick_Class4.java");
}
+
+ public void testJavaCompletion1() throws Throwable {
+ copyFileToProject("main.xml", "res/layout/main.xml");
+ doTestJavaCompletion("p1.p2");
+ }
+
+ public void testJavaCompletion2() throws Throwable {
+ copyFileToProject("main.xml", "res/layout/main.xml");
+ doTestJavaCompletion("p1.p2");
+ }
+
+ public void testJavaCompletion3() throws Throwable {
+ copyFileToProject("main.xml", "res/layout/main.xml");
+ doTestJavaCompletion("p1.p2");
+ }
+
+ public void testJavaIdCompletion() throws Throwable {
+ copyFileToProject("main.xml", "res/layout/main.xml");
+ doTestJavaCompletion("p1.p2");
+ }
+
+ public void testJavaHighlighting1() throws Throwable {
+ copyFileToProject("main.xml", "res/layout/main.xml");
+ doTestJavaHighlighting("p1.p2");
+ }
+
+ public void testJavaHighlighting2() throws Throwable {
+ copyFileToProject("main.xml", "res/layout/main.xml");
+ doTestJavaHighlighting("p1");
+ }
+
+ public void testJavaHighlighting3() throws Throwable {
+ copyFileToProject("main.xml", "res/layout/main.xml");
+ doTestJavaHighlighting("p1.p2");
+ }
+
+ public void testJavaHighlighting4() throws Throwable {
+ copyFileToProject("main.xml", "res/layout/main.xml");
+ doTestJavaHighlighting("p1.p2");
+ }
+
+ public void testJavaHighlighting5() throws Throwable {
+ copyFileToProject("main.xml", "res/layout/main.xml");
+ doTestJavaHighlighting("p1");
+ }
}
diff --git a/plugins/android/testSrc/org/jetbrains/android/dom/AndroidManifestDomTest.java b/plugins/android/testSrc/org/jetbrains/android/dom/AndroidManifestDomTest.java
index 5255eafb741f..877c73d8c318 100644
--- a/plugins/android/testSrc/org/jetbrains/android/dom/AndroidManifestDomTest.java
+++ b/plugins/android/testSrc/org/jetbrains/android/dom/AndroidManifestDomTest.java
@@ -192,4 +192,11 @@ public class AndroidManifestDomTest extends AndroidDomTest {
copyFileToProject("myIntResource.xml", "res/values/myIntResource.xml");
doTestCompletion();
}
+
+ public void testJavaHighlighting() throws Throwable {
+ copyFileToProject("PermissionsManifest.xml", "AndroidManifest.xml");
+ copyFileToProject("Manifest.java", "src/p1/p2/Manifest.java");
+ doTestJavaHighlighting("p1.p2");
+ }
+
}
diff --git a/plugins/android/testSrc/org/jetbrains/android/dom/AndroidValueResourcesTest.java b/plugins/android/testSrc/org/jetbrains/android/dom/AndroidValueResourcesTest.java
index 93c97fe11840..e6b46fa6ff15 100644
--- a/plugins/android/testSrc/org/jetbrains/android/dom/AndroidValueResourcesTest.java
+++ b/plugins/android/testSrc/org/jetbrains/android/dom/AndroidValueResourcesTest.java
@@ -215,4 +215,34 @@ public class AndroidValueResourcesTest extends AndroidDomTest {
}.execute();
myFixture.checkResultByFile(testFolder + '/' + getTestName(true) + "_after.xml", true);
}
+
+ public void testJavaCompletion1() throws Throwable {
+ copyFileToProject("value_resources.xml", "res/values/value_resources.xml");
+ doTestJavaCompletion("p1.p2");
+ }
+
+ public void testJavaCompletion2() throws Throwable {
+ copyFileToProject("value_resources.xml", "res/values/value_resources.xml");
+ doTestJavaCompletion("p1.p2");
+ }
+
+ public void testJavaCompletion3() throws Throwable {
+ copyFileToProject("value_resources.xml", "res/values/value_resources.xml");
+ doTestJavaCompletion("p1.p2");
+ }
+
+ public void testJavaCompletion4() throws Throwable {
+ copyFileToProject("value_resources.xml", "res/values/value_resources.xml");
+ doTestJavaCompletion("p1.p2");
+ }
+
+ public void testJavaHighlighting1() throws Throwable {
+ copyFileToProject("value_resources.xml", "res/values/value_resources.xml");
+ doTestJavaHighlighting("p1.p2");
+ }
+
+ public void testJavaHighlighting2() throws Throwable {
+ copyFileToProject("value_resources.xml", "res/values/value_resources.xml");
+ doTestJavaHighlighting("p1.p2");
+ }
}