diff --git a/plugins/android/resources/messages/AndroidBundle.properties b/plugins/android/resources/messages/AndroidBundle.properties index 9336260646ca..1ab856936ffa 100644 --- a/plugins/android/resources/messages/AndroidBundle.properties +++ b/plugins/android/resources/messages/AndroidBundle.properties @@ -214,4 +214,7 @@ android.run.configuration.logcat.tab.title=Logcat android.facet.settings.apk.path.label=APK path: android.run.confguration.deploy.and.install.check.box=Deplo&y application android.manifest.debuggable.attribute.not.true.warning=The manifest 'debuggable' attribute isn't set to 'true'.\nYou have to set it to true in order to debug on a device.\nWould you like to do it? -android.logcat.no.android.facets.error=There is no Android facets in the project \ No newline at end of file +android.logcat.no.android.facets.error=There is no Android facets in the project +android.facet.compiler.settings.manifest.title=Manifest +android.facet.settings.compiler.manifest.from.structure=Use AndroidManifest.xml file specified at "Structure" section +android.facet.settings.compiler.manifest.use.custom=Use custom manifest file: \ No newline at end of file diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java index f54ecf418262..41882f0b06fa 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidAptCompiler.java @@ -254,15 +254,16 @@ public class AndroidAptCompiler implements SourceGeneratingCompiler { if (target != null) { AndroidCompileUtil.createSourceRootIfNotExist(sourceRootPath, module); String assetsDirPath = assetsDir != null ? assetsDir.getPath() : null; - VirtualFile manifestFile = AndroidRootUtil.getManifestFile(module); - assert manifestFile != null; - String manifestPath = manifestFile.getPath(); - items.add(new AptGenerationItem(module, manifestPath, resPaths, assetsDirPath, sourceRootPath, target, - packageName, false)); - - for (String libPackage : AndroidUtils.getDepLibsPackages(module)) { + VirtualFile manifestFile = AndroidRootUtil.getManifestFileForCompiler(facet); + if (manifestFile != null) { + String manifestPath = manifestFile.getPath(); items.add(new AptGenerationItem(module, manifestPath, resPaths, assetsDirPath, sourceRootPath, target, - libPackage, true)); + packageName, false)); + + for (String libPackage : AndroidUtils.getDepLibsPackages(module)) { + items.add(new AptGenerationItem(module, manifestPath, resPaths, assetsDirPath, sourceRootPath, target, + libPackage, true)); + } } } } diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidPackagingCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidPackagingCompiler.java index dd54fb126649..e3d2a7790615 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidPackagingCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidPackagingCompiler.java @@ -92,7 +92,7 @@ public class AndroidPackagingCompiler implements PackagingCompiler { for (Module module : affectedModules) { AndroidFacet facet = AndroidFacet.getInstance(module); if (facet != null && !facet.getConfiguration().LIBRARY_PROJECT) { - VirtualFile manifestFile = AndroidRootUtil.getManifestFile(module); + VirtualFile manifestFile = AndroidRootUtil.getManifestFileForCompiler(facet); VirtualFile[] sourceRoots = getSourceRootsForModuleAndDependencies(module); if (manifestFile != null) { AndroidFacetConfiguration configuration = facet.getConfiguration(); diff --git a/plugins/android/src/org/jetbrains/android/compiler/AndroidResourcesPackagingCompiler.java b/plugins/android/src/org/jetbrains/android/compiler/AndroidResourcesPackagingCompiler.java index d0a94b84760b..699cc023ff29 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/AndroidResourcesPackagingCompiler.java +++ b/plugins/android/src/org/jetbrains/android/compiler/AndroidResourcesPackagingCompiler.java @@ -45,7 +45,7 @@ public class AndroidResourcesPackagingCompiler implements ClassPostProcessingCom for (Module module : affectedModules) { AndroidFacet facet = AndroidFacet.getInstance(module); if (facet != null && !facet.getConfiguration().LIBRARY_PROJECT) { - VirtualFile manifestFile = AndroidRootUtil.getManifestFile(module); + VirtualFile manifestFile = AndroidRootUtil.getManifestFileForCompiler(facet); VirtualFile assetsDir = AndroidRootUtil.getAssetsDir(module); if (manifestFile != null) { AndroidFacetConfiguration configuration = facet.getConfiguration(); diff --git a/plugins/android/src/org/jetbrains/android/compiler/ResourcesValidityState.java b/plugins/android/src/org/jetbrains/android/compiler/ResourcesValidityState.java index af773936be4c..93a0d69ee056 100644 --- a/plugins/android/src/org/jetbrains/android/compiler/ResourcesValidityState.java +++ b/plugins/android/src/org/jetbrains/android/compiler/ResourcesValidityState.java @@ -49,7 +49,7 @@ public class ResourcesValidityState implements ValidityState { IAndroidTarget target = platform != null ? platform.getTarget() : null; myAndroidTargetName = target != null ? target.getFullName() : ""; - VirtualFile manifestFile = AndroidRootUtil.getManifestFile(module); + VirtualFile manifestFile = AndroidRootUtil.getManifestFileForCompiler(facet); if (manifestFile != null) { myResourceTimestamps.put(manifestFile.getPath(), manifestFile.getTimeStamp()); } @@ -58,7 +58,7 @@ public class ResourcesValidityState implements ValidityState { collectFiles(resourcesDir); } for (AndroidFacet depFacet : AndroidUtils.getAllAndroidDependencies(module, true)) { - VirtualFile depManifest = AndroidRootUtil.getManifestFile(depFacet.getModule()); + VirtualFile depManifest = AndroidRootUtil.getManifestFileForCompiler(depFacet); if (depManifest != null) { myResourceTimestamps.put(depManifest.getPath(), depManifest.getTimeStamp()); } diff --git a/plugins/android/src/org/jetbrains/android/facet/AndroidFacetConfiguration.java b/plugins/android/src/org/jetbrains/android/facet/AndroidFacetConfiguration.java index 2127535251f6..9cc8d2e7309f 100644 --- a/plugins/android/src/org/jetbrains/android/facet/AndroidFacetConfiguration.java +++ b/plugins/android/src/org/jetbrains/android/facet/AndroidFacetConfiguration.java @@ -57,6 +57,9 @@ public class AndroidFacetConfiguration implements FacetConfiguration { public boolean USE_CUSTOM_APK_RESOURCE_FOLDER = false; public String CUSTOM_APK_RESOURCE_FOLDER = ""; + public boolean USE_CUSTOM_COMPILER_MANIFEST = false; + public String CUSTOM_COMPILER_MANIFEST = ""; + public String APK_PATH = ""; public boolean ADD_ANDROID_LIBRARY = true; diff --git a/plugins/android/src/org/jetbrains/android/facet/AndroidFacetEditorTab.form b/plugins/android/src/org/jetbrains/android/facet/AndroidFacetEditorTab.form index 76cbc0dc0bbd..cc727652b412 100644 --- a/plugins/android/src/org/jetbrains/android/facet/AndroidFacetEditorTab.form +++ b/plugins/android/src/org/jetbrains/android/facet/AndroidFacetEditorTab.form @@ -3,7 +3,7 @@ - + @@ -176,7 +176,7 @@ - + @@ -187,7 +187,7 @@ - + @@ -227,7 +227,7 @@ - + @@ -259,7 +259,7 @@ - + @@ -312,7 +312,7 @@ - + @@ -323,6 +323,39 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -342,5 +375,9 @@ + + + + diff --git a/plugins/android/src/org/jetbrains/android/facet/AndroidFacetEditorTab.java b/plugins/android/src/org/jetbrains/android/facet/AndroidFacetEditorTab.java index 6ca0c770a7a8..a2e8b416cae3 100644 --- a/plugins/android/src/org/jetbrains/android/facet/AndroidFacetEditorTab.java +++ b/plugins/android/src/org/jetbrains/android/facet/AndroidFacetEditorTab.java @@ -103,6 +103,9 @@ public class AndroidFacetEditorTab extends FacetEditorTab { private JCheckBox myGenerateUnsignedApk; private ComboboxWithBrowseButton myApkPathCombo; private JLabel myApkPathLabel; + private JRadioButton myUseCompilerManifestFromStructureRadio; + private JRadioButton myUseCustomCompilerManifestRadio; + private TextFieldWithBrowseButton myCustomCompilerManifestPathField; public AndroidFacetEditorTab(FacetEditorContext context, AndroidFacetConfiguration androidFacetConfiguration) { final Project project = context.getProject(); @@ -130,6 +133,9 @@ public class AndroidFacetEditorTab extends FacetEditorTab { myCustomAptSourceDirField.getButton().addActionListener(new MyFolderFieldListener(myCustomAptSourceDirField, AndroidAptCompiler.getCustomResourceDirForApt(facet), false)); + myCustomCompilerManifestPathField.getButton().addActionListener(new MyFolderFieldListener(myCustomCompilerManifestPathField, + AndroidRootUtil.getManifestFileForCompiler(facet), + true)); myPlatformChooser.addListener(new AndroidPlatformChooserListener() { @Override @@ -176,6 +182,15 @@ public class AndroidFacetEditorTab extends FacetEditorTab { myUseCustomSourceDirectoryRadio.addActionListener(listener); myUseAptResDirectoryFromPathRadio.addActionListener(listener); + listener = new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + myCustomCompilerManifestPathField.setEnabled(myUseCustomCompilerManifestRadio.isSelected()); + } + }; + myUseCustomCompilerManifestRadio.addActionListener(listener); + myUseCompilerManifestFromStructureRadio.addActionListener(listener); + myIsLibraryProjectCheckbox.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { @@ -329,10 +344,17 @@ public class AndroidFacetEditorTab extends FacetEditorTab { if (myUseCustomSourceDirectoryRadio.isSelected() != myConfiguration.USE_CUSTOM_APK_RESOURCE_FOLDER) { return true; } - if (checkRelativePath(myConfiguration.CUSTOM_APK_RESOURCE_FOLDER, myCustomAptSourceDirField.getText())) { return true; } + + if (myUseCustomCompilerManifestRadio.isSelected() != myConfiguration.USE_CUSTOM_COMPILER_MANIFEST) { + return true; + } + if (checkRelativePath(myConfiguration.CUSTOM_COMPILER_MANIFEST, myCustomCompilerManifestPathField.getText())) { + return true; + } + if (myCopyResourcesFromArtifacts.isSelected() != myConfiguration.COPY_RESOURCES_FROM_ARTIFACTS) { return true; } @@ -495,6 +517,12 @@ public class AndroidFacetEditorTab extends FacetEditorTab { } myConfiguration.USE_CUSTOM_APK_RESOURCE_FOLDER = useCustomAptSrc; + boolean useCustomCompilerManifest = myUseCustomCompilerManifestRadio.isSelected(); + if (myConfiguration.USE_CUSTOM_COMPILER_MANIFEST != useCustomCompilerManifest) { + runApt = true; + } + myConfiguration.USE_CUSTOM_COMPILER_MANIFEST = useCustomCompilerManifest; + if (myConfiguration.REGENERATE_R_JAVA != myGenerateRJavaWhenChanged.isSelected()) { runApt = true; } @@ -526,6 +554,25 @@ public class AndroidFacetEditorTab extends FacetEditorTab { myConfiguration.CUSTOM_APK_RESOURCE_FOLDER = relPath != null ? '/' + relPath : ""; } + String absCompilerManifestPath = myCustomCompilerManifestPathField.getText().trim(); + if (useCustomCompilerManifest) { + if (absCompilerManifestPath.length() == 0) { + throw new ConfigurationException("AndroidManifest.xml path not specified in \"Compiler\" section"); + } + String newCustomCompilerManifestPath = '/' + getAndCheckRelativePath(absCompilerManifestPath, false); + if (!SdkConstants.FN_ANDROID_MANIFEST_XML.equals(AndroidUtils.getSimpleNameByRelativePath(newCustomCompilerManifestPath))) { + throw new ConfigurationException("Manifest file must have name AndroidManifest.xml"); + } + if (!newCustomCompilerManifestPath.equals(myConfiguration.CUSTOM_COMPILER_MANIFEST)) { + runApt = true; + } + myConfiguration.CUSTOM_COMPILER_MANIFEST = newCustomCompilerManifestPath; + } + else { + String relPath = toRelativePath(absCompilerManifestPath); + myConfiguration.CUSTOM_COMPILER_MANIFEST = relPath != null ? '/' + relPath : ""; + } + final AndroidPlatform platform = myPlatformChooser.getSelectedPlatform(); myConfiguration.setAndroidPlatform(platform); final AndroidFacet facet = myConfiguration.getFacet(); @@ -657,6 +704,14 @@ public class AndroidFacetEditorTab extends FacetEditorTab { myCustomAptSourceDirField.setText(aptSourceAbsPath != null ? aptSourceAbsPath : ""); myCustomAptSourceDirField.setEnabled(configuration.USE_CUSTOM_APK_RESOURCE_FOLDER); + myUseCustomCompilerManifestRadio.setSelected(configuration.USE_CUSTOM_COMPILER_MANIFEST); + myUseCompilerManifestFromStructureRadio.setSelected(!configuration.USE_CUSTOM_COMPILER_MANIFEST); + + String compilerManifestPath = configuration.CUSTOM_COMPILER_MANIFEST; + String compilerManifestAbsPath = compilerManifestPath.length() > 0 ? toAbsolutePath(compilerManifestPath) : ""; + myCustomCompilerManifestPathField.setText(compilerManifestAbsPath != null ? compilerManifestAbsPath : ""); + myCustomCompilerManifestPathField.setEnabled(configuration.USE_CUSTOM_COMPILER_MANIFEST); + String apkPath = configuration.APK_PATH; String apkAbsPath = apkPath.length() > 0 ? toAbsolutePath(apkPath) : ""; myApkPathCombo.getComboBox().getEditor().setItem(apkAbsPath != null ? apkAbsPath : ""); diff --git a/plugins/android/src/org/jetbrains/android/facet/AndroidRootUtil.java b/plugins/android/src/org/jetbrains/android/facet/AndroidRootUtil.java index 62dcd9f1128e..e63fa861d677 100644 --- a/plugins/android/src/org/jetbrains/android/facet/AndroidRootUtil.java +++ b/plugins/android/src/org/jetbrains/android/facet/AndroidRootUtil.java @@ -47,13 +47,18 @@ public class AndroidRootUtil { public static VirtualFile getManifestFile(@NotNull Module module) { AndroidFacet facet = AndroidFacet.getInstance(module); return facet == null ? null : getFileByRelativeModulePath(module, facet.getConfiguration().MANIFEST_FILE_RELATIVE_PATH, true); + } - /*VirtualFile[] files = ModuleRootManager.getInstance(module).getContentRoots(); - for (VirtualFile contentRoot : files) { - VirtualFile manifest = contentRoot.findChild(SdkConstants.FN_ANDROID_MANIFEST_XML); - if (manifest != null) return manifest; - } - return null;*/ + @Nullable + public static VirtualFile getCustomManifestFileForCompiler(@NotNull AndroidFacet facet) { + return getFileByRelativeModulePath(facet.getModule(), facet.getConfiguration().CUSTOM_COMPILER_MANIFEST, false); + } + + @Nullable + public static VirtualFile getManifestFileForCompiler(AndroidFacet facet) { + return facet.getConfiguration().USE_CUSTOM_COMPILER_MANIFEST + ? getCustomManifestFileForCompiler(facet) + : getManifestFile(facet.getModule()); } @Nullable