aboutsummaryrefslogtreecommitdiffstats
path: root/eclipse/plugins
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-03-02 22:54:20 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-03-02 22:54:20 -0800
commit382f18c205f459fdd9ff6c0657beadcbfe3c5b01 (patch)
treecf087c09020d087526ef925668e044e39950bbf9 /eclipse/plugins
parent76bc028c745906e691284c685e34e72b5ccf06b5 (diff)
downloadsdk-382f18c205f459fdd9ff6c0657beadcbfe3c5b01.zip
sdk-382f18c205f459fdd9ff6c0657beadcbfe3c5b01.tar.gz
sdk-382f18c205f459fdd9ff6c0657beadcbfe3c5b01.tar.bz2
auto import from //depot/cupcake/@137055
Diffstat (limited to 'eclipse/plugins')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/icons/new_adt_project.pngbin0 -> 664 bytes
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/icons/new_xml.pngbin0 -> 3577 bytes
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml35
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java100
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java122
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/BaseBuilder.java89
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/DexWrapper.java7
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/PreCompilerBuilder.java14
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/preferences/AndroidPreferencePage.java74
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainerInitializer.java2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/properties/AndroidPropertyPage.java49
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetData.java25
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetParser.java78
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/Sdk.java164
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/actions/NewProjectAction.java34
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/actions/NewXmlFileAction.java34
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/actions/OpenWizardAction.java139
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectWizard.java20
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/AndroidConstants.java7
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/AndroidEditor.java26
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/DescriptorsUtils.java2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/GraphicalLayoutEditor.java121
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutEditor.java30
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/AndroidManifestDescriptors.java2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ClassAttributeDescriptor.java2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/UiTreeBlock.java26
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/NewXmlFileCreationPage.java209
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/xml/descriptors/XmlDescriptors.java49
28 files changed, 1134 insertions, 326 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/icons/new_adt_project.png b/eclipse/plugins/com.android.ide.eclipse.adt/icons/new_adt_project.png
new file mode 100644
index 0000000..0f0e883
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/icons/new_adt_project.png
Binary files differ
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/icons/new_xml.png b/eclipse/plugins/com.android.ide.eclipse.adt/icons/new_xml.png
new file mode 100644
index 0000000..8273185
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/icons/new_xml.png
Binary files differ
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml b/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml
index f7c366d..d6c9ac1 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml
@@ -18,6 +18,14 @@
<persistent value="true"/>
</extension>
<extension
+ id="com.android.ide.eclipse.common.aapt2Problem"
+ name="Android AAPT Problem"
+ point="org.eclipse.core.resources.markers">
+ <super type="org.eclipse.core.resources.problemmarker"/>
+ <super type="org.eclipse.core.resources.textmarker"/>
+ <persistent value="true"/>
+ </extension>
+ <extension
id="com.android.ide.eclipse.common.aidlProblem"
name="Android AIDL Problem"
point="org.eclipse.core.resources.markers">
@@ -464,4 +472,31 @@
</enabledWhen>
</page>
</extension>
+ <extension
+ point="org.eclipse.ui.actionSets">
+ <actionSet
+ description="Android Wizards"
+ id="adt.actionSet1"
+ label="Android Wizards"
+ visible="true">
+ <action
+ class="com.android.ide.eclipse.adt.wizards.actions.NewProjectAction"
+ icon="icons/new_adt_project.png"
+ id="com.android.ide.eclipse.adt.wizards.actions.NewProjectAction"
+ label="New Android Project"
+ style="push"
+ toolbarPath="android_project"
+ tooltip="Opens a wizard to help create a new Android project">
+ </action>
+ <action
+ class="com.android.ide.eclipse.adt.wizards.actions.NewXmlFileAction"
+ icon="icons/new_xml.png"
+ id="com.android.ide.eclipse.adt.wizards.actions.NewXmlFileAction"
+ label="New Android XML File"
+ style="push"
+ toolbarPath="android_project"
+ tooltip="Opens a wizard to help create a new Android XML file">
+ </action>
+ </actionSet>
+ </extension>
</plugin>
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java
index 9aa9354..61be3e5 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java
@@ -28,6 +28,7 @@ import com.android.ide.eclipse.adt.project.internal.AndroidClasspathContainerIni
import com.android.ide.eclipse.adt.sdk.AndroidTargetParser;
import com.android.ide.eclipse.adt.sdk.LoadStatus;
import com.android.ide.eclipse.adt.sdk.Sdk;
+import com.android.ide.eclipse.adt.sdk.Sdk.ITargetChangeListener;
import com.android.ide.eclipse.common.AndroidConstants;
import com.android.ide.eclipse.common.EclipseUiHelper;
import com.android.ide.eclipse.common.SdkStatsHelper;
@@ -173,7 +174,8 @@ public class AdtPlugin extends AbstractUIPlugin {
private final ArrayList<IJavaProject> mPostLoadProjectsToCheck = new ArrayList<IJavaProject>();
private ResourceMonitor mResourceMonitor;
- private ArrayList<Runnable> mResourceRefreshListener = new ArrayList<Runnable>();
+ private ArrayList<ITargetChangeListener> mTargetChangeListeners =
+ new ArrayList<ITargetChangeListener>();
/**
* Custom PrintStream for Dx output. This class overrides the method
@@ -861,7 +863,6 @@ public class AdtPlugin extends AbstractUIPlugin {
/**
* Returns the lock object for SDK loading. If you wish to do things while the SDK is loading,
* you must synchronize on this object.
- * @return
*/
public final Object getSdkLockObject() {
return mPostLoadProjectsToResolve;
@@ -986,7 +987,7 @@ public class AdtPlugin extends AbstractUIPlugin {
Constants.BUNDLE_VERSION);
Version version = new Version(versionString);
- SdkStatsHelper.pingUsageServer("editors", version); //$NON-NLS-1$
+ SdkStatsHelper.pingUsageServer("adt", version); //$NON-NLS-1$
return Status.OK_STATUS;
} catch (Throwable t) {
@@ -1019,24 +1020,27 @@ public class AdtPlugin extends AbstractUIPlugin {
progress.setTaskName(Messages.AdtPlugin_Parsing_Resources);
- for (IAndroidTarget target : sdk.getTargets()) {
- IStatus status = new AndroidTargetParser(target).run(progress);
- if (status.getCode() != IStatus.OK) {
- synchronized (getSdkLockObject()) {
- mSdkIsLoaded = LoadStatus.FAILED;
- mPostLoadProjectsToResolve.clear();
+ int n = sdk.getTargets().length;
+ if (n > 0) {
+ int w = 60 / n;
+ for (IAndroidTarget target : sdk.getTargets()) {
+ SubMonitor p2 = progress.newChild(w);
+ IStatus status = new AndroidTargetParser(target).run(p2);
+ if (status.getCode() != IStatus.OK) {
+ synchronized (getSdkLockObject()) {
+ mSdkIsLoaded = LoadStatus.FAILED;
+ mPostLoadProjectsToResolve.clear();
+ }
+ return status;
}
- return status;
}
}
- // FIXME: move this per platform, or somewhere else.
- progress = SubMonitor.convert(monitor,
- Messages.AdtPlugin_Parsing_Resources, 20);
-
synchronized (getSdkLockObject()) {
mSdkIsLoaded = LoadStatus.LOADED;
+ progress.setTaskName("Check Projects");
+
// check the projects that need checking.
// The method modifies the list (it removes the project that
// do not need to be resolved again).
@@ -1052,25 +1056,33 @@ public class AdtPlugin extends AbstractUIPlugin {
AndroidClasspathContainerInitializer.updateProjects(array);
mPostLoadProjectsToResolve.clear();
}
+
+ progress.worked(10);
}
}
// Notify resource changed listeners
- progress.subTask("Refresh UI");
- progress.setWorkRemaining(mResourceRefreshListener.size());
+ progress.setTaskName("Refresh UI");
+ progress.setWorkRemaining(mTargetChangeListeners.size());
// Clone the list before iterating, to avoid Concurrent Modification
// exceptions
- List<Runnable> listeners = (List<Runnable>)mResourceRefreshListener.clone();
- for (Runnable listener : listeners) {
- try {
- AdtPlugin.getDisplay().syncExec(listener);
- } catch (Exception e) {
- AdtPlugin.log(e, "ResourceRefreshListener Failed"); //$NON-NLS-1$
- } finally {
- progress.worked(1);
+ final List<ITargetChangeListener> listeners =
+ (List<ITargetChangeListener>)mTargetChangeListeners.clone();
+ final SubMonitor progress2 = progress;
+ AdtPlugin.getDisplay().syncExec(new Runnable() {
+ public void run() {
+ for (ITargetChangeListener listener : listeners) {
+ try {
+ listener.onTargetsLoaded();
+ } catch (Exception e) {
+ AdtPlugin.log(e, "Failed to update a TargetChangeListener."); //$NON-NLS-1$
+ } finally {
+ progress2.worked(1);
+ }
+ }
}
- }
+ });
} finally {
if (monitor != null) {
monitor.done();
@@ -1316,12 +1328,42 @@ public class AdtPlugin extends AbstractUIPlugin {
}, IResourceDelta.ADDED | IResourceDelta.CHANGED);
}
- public void addResourceChangedListener(Runnable resourceRefreshListener) {
- mResourceRefreshListener.add(resourceRefreshListener);
+ /**
+ * Adds a new {@link ITargetChangeListener} to be notified when a new SDK is loaded, or when
+ * a project has its target changed.
+ */
+ public void addTargetListener(ITargetChangeListener listener) {
+ mTargetChangeListeners.add(listener);
+ }
+
+ /**
+ * Removes an existing {@link ITargetChangeListener}.
+ * @see #addTargetListener(ITargetChangeListener)
+ */
+ public void removeTargetListener(ITargetChangeListener listener) {
+ mTargetChangeListeners.remove(listener);
}
- public void removeResourceChangedListener(Runnable resourceRefreshListener) {
- mResourceRefreshListener.remove(resourceRefreshListener);
+ /**
+ * Updates all the {@link ITargetChangeListener} that a target has changed for a given project.
+ * <p/>Only editors related to that project should reload.
+ */
+ @SuppressWarnings("unchecked")
+ public void updateTargetListener(final IProject project) {
+ final List<ITargetChangeListener> listeners =
+ (List<ITargetChangeListener>)mTargetChangeListeners.clone();
+
+ AdtPlugin.getDisplay().asyncExec(new Runnable() {
+ public void run() {
+ for (ITargetChangeListener listener : listeners) {
+ try {
+ listener.onProjectTargetChange(project);
+ } catch (Exception e) {
+ AdtPlugin.log(e, "Failed to update a TargetChangeListener."); //$NON-NLS-1$
+ }
+ }
+ }
+ });
}
public static synchronized OutputStream getErrorStream() {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java
index 96068c2..e71ae47 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java
@@ -203,6 +203,9 @@ public class ApkBuilder extends BaseBuilder {
// get a project object
IProject project = getProject();
+ // Top level check to make sure the build can move forward.
+ abortOnBadSetup(project);
+
// get the list of referenced projects.
IProject[] referencedProjects = ProjectHelper.getReferencedProjects(project);
IJavaProject[] referencedJavaProjects = getJavaProjects(referencedProjects);
@@ -262,19 +265,79 @@ public class ApkBuilder extends BaseBuilder {
}
}
}
+
+ // store the build status in the persistent storage
+ saveProjectBooleanProperty(PROPERTY_CONVERT_TO_DEX , mConvertToDex);
+ saveProjectBooleanProperty(PROPERTY_PACKAGE_RESOURCES, mPackageResources);
+ saveProjectBooleanProperty(PROPERTY_BUILD_APK, mBuildFinalPackage);
+
+ if (dv != null && dv.mXmlError) {
+ AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project,
+ Messages.Xml_Error);
+
+ // if there was some XML errors, we just return w/o doing
+ // anything since we've put some markers in the files anyway
+ return referencedProjects;
+ }
+
+ if (outputFolder == null) {
+ // mark project and exit
+ markProject(AdtConstants.MARKER_ADT, Messages.Failed_To_Get_Output,
+ IMarker.SEVERITY_ERROR);
+ return referencedProjects;
+ }
+
+ // first thing we do is check that the SDK directory has been setup.
+ String osSdkFolder = AdtPlugin.getOsSdkFolder();
+
+ if (osSdkFolder.length() == 0) {
+ // this has already been checked in the precompiler. Therefore,
+ // while we do have to cancel the build, we don't have to return
+ // any error or throw anything.
+ return referencedProjects;
+ }
+
+ // get the extra configs for the project.
+ // The map contains (name, filter) where 'name' is a name to be used in the apk filename,
+ // and filter is the resource filter to be used in the aapt -c parameters to restrict
+ // which resource configurations to package in the apk.
+ Map<String, String> configs = Sdk.getCurrent().getProjectApkConfigs(project);
// do some extra check, in case the output files are not present. This
// will force to recreate them.
IResource tmp = null;
- if (mPackageResources == false && outputFolder != null) {
+ if (mPackageResources == false) {
+ // check the full resource package
tmp = outputFolder.findMember(AndroidConstants.FN_RESOURCES_AP_);
if (tmp == null || tmp.exists() == false) {
mPackageResources = true;
mBuildFinalPackage = true;
+ } else {
+ // if the full package is present, we check the filtered resource packages as well
+ if (configs != null) {
+ Set<Entry<String, String>> entrySet = configs.entrySet();
+
+ for (Entry<String, String> entry : entrySet) {
+ String filename = String.format(AndroidConstants.FN_RESOURCES_S_AP_,
+ entry.getKey());
+
+ tmp = outputFolder.findMember(filename);
+ if (tmp == null || (tmp instanceof IFile &&
+ tmp.exists() == false)) {
+ String msg = String.format(Messages.s_Missing_Repackaging, filename);
+ AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg);
+ mPackageResources = true;
+ mBuildFinalPackage = true;
+ break;
+ }
+ }
+ }
}
}
- if (mConvertToDex == false && outputFolder != null) {
+
+ // check classes.dex is present. If not we force to recreate it.
+ if (mConvertToDex == false) {
tmp = outputFolder.findMember(AndroidConstants.FN_CLASSES_DEX);
if (tmp == null || tmp.exists() == false) {
mConvertToDex = true;
@@ -282,22 +345,17 @@ public class ApkBuilder extends BaseBuilder {
}
}
- // get the extra configs for the project. This will give us a list of custom apk
- // to build based on a restricted set of resources.
- Map<String, String> configs = Sdk.getCurrent().getProjectApkConfigs(project);
-
// also check the final file(s)!
String finalPackageName = getFileName(project, null /*config*/);
- if (mBuildFinalPackage == false && outputFolder != null) {
+ if (mBuildFinalPackage == false) {
tmp = outputFolder.findMember(finalPackageName);
if (tmp == null || (tmp instanceof IFile &&
tmp.exists() == false)) {
String msg = String.format(Messages.s_Missing_Repackaging, finalPackageName);
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg);
mBuildFinalPackage = true;
- }
-
- if (configs != null) {
+ } else if (configs != null) {
+ // if the full apk is present, we check the filtered apk as well
Set<Entry<String, String>> entrySet = configs.entrySet();
for (Entry<String, String> entry : entrySet) {
@@ -306,8 +364,7 @@ public class ApkBuilder extends BaseBuilder {
tmp = outputFolder.findMember(filename);
if (tmp == null || (tmp instanceof IFile &&
tmp.exists() == false)) {
- String msg = String.format(Messages.s_Missing_Repackaging,
- finalPackageName);
+ String msg = String.format(Messages.s_Missing_Repackaging, filename);
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, msg);
mBuildFinalPackage = true;
break;
@@ -316,41 +373,6 @@ public class ApkBuilder extends BaseBuilder {
}
}
- // store the build status in the persistent storage
- saveProjectBooleanProperty(PROPERTY_CONVERT_TO_DEX , mConvertToDex);
- saveProjectBooleanProperty(PROPERTY_PACKAGE_RESOURCES, mPackageResources);
- saveProjectBooleanProperty(PROPERTY_BUILD_APK, mBuildFinalPackage);
-
- // At this point, we can abort the build if we have to, as we have computed
- // our resource delta and stored the result.
- abortOnBadSetup(project);
-
- if (dv != null && dv.mXmlError) {
- AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project,
- Messages.Xml_Error);
-
- // if there was some XML errors, we just return w/o doing
- // anything since we've put some markers in the files anyway
- return referencedProjects;
- }
-
- if (outputFolder == null) {
- // mark project and exit
- markProject(AdtConstants.MARKER_ADT, Messages.Failed_To_Get_Output,
- IMarker.SEVERITY_ERROR);
- return referencedProjects;
- }
-
- // first thing we do is check that the SDK directory has been setup.
- String osSdkFolder = AdtPlugin.getOsSdkFolder();
-
- if (osSdkFolder.length() == 0) {
- // this has already been checked in the precompiler. Therefore,
- // while we do have to cancel the build, we don't have to return
- // any error or throw anything.
- return referencedProjects;
- }
-
// at this point we know if we need to recreate the temporary apk
// or the dex file, but we don't know if we simply need to recreate them
// because they are missing
@@ -396,6 +418,9 @@ public class ApkBuilder extends BaseBuilder {
// first we check if we need to package the resources.
if (mPackageResources) {
+ // remove some aapt_package only markers.
+ removeMarkersFromContainer(project, AndroidConstants.MARKER_AAPT_PACKAGE);
+
// need to figure out some path before we can execute aapt;
// resource to the AndroidManifest.xml file
@@ -552,7 +577,8 @@ public class ApkBuilder extends BaseBuilder {
* @param osAssetsPath The path to the assets folder. This can be null.
* @param osOutFilePath The path to the temporary resource file to create.
* @param configFilter The configuration filter for the resources to include
- * (used with -c option)
+ * (used with -c option, for example "port,en,fr" to include portrait, English and French
+ * resources.)
* @return true if success, false otherwise.
*/
private boolean executeAapt(IProject project, String osManifestPath,
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/BaseBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/BaseBuilder.java
index 6b0810a..e2e9728 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/BaseBuilder.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/BaseBuilder.java
@@ -149,6 +149,15 @@ abstract class BaseBuilder extends IncrementalProjectBuilder {
private final static Pattern sPattern8Line1 = Pattern.compile(
"^(invalid resource directory name): (.*)$"); //$NON-NLS-1$
+ /**
+ * 2 line aapt error<br>
+ * "ERROR: Invalid configuration: foo"<br>
+ * " ^^^"<br>
+ * There's no need to parse the 2nd line.
+ */
+ private final static Pattern sPattern9Line1 = Pattern.compile(
+ "^Invalid configuration: (.+)$"); //$NON-NLS-1$
+
/** SAX Parser factory. */
private SAXParserFactory mParserFactory;
@@ -440,8 +449,8 @@ abstract class BaseBuilder extends IncrementalProjectBuilder {
String location = m.group(1);
// check the values and attempt to mark the file.
- if (checkAndMark(location, lineStr, msg, osRoot,
- project, IMarker.SEVERITY_ERROR) == false) {
+ if (checkAndMark(location, lineStr, msg, osRoot, project,
+ AndroidConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_ERROR) == false) {
return true;
}
continue;
@@ -465,7 +474,7 @@ abstract class BaseBuilder extends IncrementalProjectBuilder {
// display the error
if (checkAndMark(location, null, msg, osRoot, project,
- IMarker.SEVERITY_ERROR) == false) {
+ AndroidConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_ERROR) == false) {
return true;
}
@@ -488,8 +497,8 @@ abstract class BaseBuilder extends IncrementalProjectBuilder {
String lineStr = m.group(2);
// check the values and attempt to mark the file.
- if (checkAndMark(location, lineStr, msg, osRoot,
- project, IMarker.SEVERITY_ERROR) == false) {
+ if (checkAndMark(location, lineStr, msg, osRoot, project,
+ AndroidConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_ERROR) == false) {
return true;
}
continue;
@@ -502,8 +511,8 @@ abstract class BaseBuilder extends IncrementalProjectBuilder {
String msg = m.group(3);
// check the values and attempt to mark the file.
- if (checkAndMark(location, lineStr, msg, osRoot,
- project, IMarker.SEVERITY_ERROR) == false) {
+ if (checkAndMark(location, lineStr, msg, osRoot, project,
+ AndroidConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_ERROR) == false) {
return true;
}
@@ -526,8 +535,8 @@ abstract class BaseBuilder extends IncrementalProjectBuilder {
String lineStr = m.group(2);
// check the values and attempt to mark the file.
- if (checkAndMark(location, lineStr, msg, osRoot,
- project, IMarker.SEVERITY_ERROR) == false) {
+ if (checkAndMark(location, lineStr, msg, osRoot, project,
+ AndroidConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_ERROR) == false) {
return true;
}
@@ -542,8 +551,8 @@ abstract class BaseBuilder extends IncrementalProjectBuilder {
String msg = m.group(3);
// check the values and attempt to mark the file.
- if (checkAndMark(location, lineStr, msg, osRoot,
- project,IMarker.SEVERITY_WARNING) == false) {
+ if (checkAndMark(location, lineStr, msg, osRoot, project,
+ AndroidConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_WARNING) == false) {
return true;
}
@@ -558,8 +567,8 @@ abstract class BaseBuilder extends IncrementalProjectBuilder {
String msg = m.group(3);
// check the values and attempt to mark the file.
- if (checkAndMark(location, lineStr, msg, osRoot,
- project, IMarker.SEVERITY_ERROR) == false) {
+ if (checkAndMark(location, lineStr, msg, osRoot, project,
+ AndroidConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_ERROR) == false) {
return true;
}
@@ -574,7 +583,25 @@ abstract class BaseBuilder extends IncrementalProjectBuilder {
// check the values and attempt to mark the file.
if (checkAndMark(location, null, msg, osRoot, project,
- IMarker.SEVERITY_ERROR) == false) {
+ AndroidConstants.MARKER_AAPT_COMPILE, IMarker.SEVERITY_ERROR) == false) {
+ return true;
+ }
+
+ // success, go to the next line
+ continue;
+ }
+
+ m = sPattern9Line1.matcher(p);
+ if (m.matches()) {
+ String badConfig = m.group(1);
+ String msg = String.format("APK Configuration filter '%1$s' is invalid", badConfig);
+
+ // skip the next line
+ i++;
+
+ // check the values and attempt to mark the file.
+ if (checkAndMark(null /*location*/, null, msg, osRoot, project,
+ AndroidConstants.MARKER_AAPT_PACKAGE, IMarker.SEVERITY_ERROR) == false) {
return true;
}
@@ -659,23 +686,25 @@ abstract class BaseBuilder extends IncrementalProjectBuilder {
/**
* Check if the parameters gotten from the error output are valid, and mark
* the file with an AAPT marker.
- * @param location
+ * @param location the full OS path of the error file. If null, the project is marked
* @param lineStr
* @param message
* @param root The root directory of the project, in OS specific format.
* @param project
+ * @param markerId The marker id to put.
* @param severity The severity of the marker to put (IMarker.SEVERITY_*)
- * @return true if the parameters were valid and the file was marked
- * sucessfully.
+ * @return true if the parameters were valid and the file was marked successfully.
*
* @see IMarker
*/
private final boolean checkAndMark(String location, String lineStr,
- String message, String root, IProject project, int severity) {
+ String message, String root, IProject project, String markerId, int severity) {
// check this is in fact a file
- File f = new File(location);
- if (f.exists() == false) {
- return false;
+ if (location != null) {
+ File f = new File(location);
+ if (f.exists() == false) {
+ return false;
+ }
}
// get the line number
@@ -692,16 +721,18 @@ abstract class BaseBuilder extends IncrementalProjectBuilder {
}
// add the marker
- IResource f2 = getResourceFromFullPath(location, root, project);
- if (f2 == null) {
- return false;
+ IResource f2 = project;
+ if (location != null) {
+ f2 = getResourceFromFullPath(location, root, project);
+ if (f2 == null) {
+ return false;
+ }
}
// check if there's a similar marker already, since aapt is launched twice
boolean markerAlreadyExists = false;
try {
- IMarker[] markers = f2.findMarkers(AndroidConstants.MARKER_AAPT, true,
- IResource.DEPTH_ZERO);
+ IMarker[] markers = f2.findMarkers(markerId, true, IResource.DEPTH_ZERO);
for (IMarker marker : markers) {
int tmpLine = marker.getAttribute(IMarker.LINE_NUMBER, -1);
@@ -732,10 +763,10 @@ abstract class BaseBuilder extends IncrementalProjectBuilder {
if (markerAlreadyExists == false) {
if (line != -1) {
- BaseProjectHelper.addMarker(f2, AndroidConstants.MARKER_AAPT, message, line,
+ BaseProjectHelper.addMarker(f2, markerId, message, line,
severity);
} else {
- BaseProjectHelper.addMarker(f2, AndroidConstants.MARKER_AAPT, message, severity);
+ BaseProjectHelper.addMarker(f2, markerId, message, severity);
}
}
@@ -851,7 +882,7 @@ abstract class BaseBuilder extends IncrementalProjectBuilder {
* Aborts the build if the SDK/project setups are broken. This does not
* display any errors.
*
- * @param javaProject The {@link IJavaProject} being compiled.
+ * @param project The {@link IJavaProject} being compiled.
* @throws CoreException
*/
protected final void abortOnBadSetup(IProject project) throws CoreException {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/DexWrapper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/DexWrapper.java
index 26d96d7..65ad4f5 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/DexWrapper.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/DexWrapper.java
@@ -57,8 +57,11 @@ public final class DexWrapper {
private Field mConsoleErr;
/**
- * Loads the dex library from a file path. The loaded library can be used with the
- * {@link DexWrapper} object returned by {@link #getWrapper()}
+ * Loads the dex library from a file path.
+ *
+ * The loaded library can be used via
+ * {@link DexWrapper#run(String, String[], boolean, PrintStream, PrintStream)}.
+ *
* @param osFilepath the location of the dex.jar file.
* @return an IStatus indicating the result of the load.
*/
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/PreCompilerBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/PreCompilerBuilder.java
index 958cac2..a0e446c 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/PreCompilerBuilder.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/PreCompilerBuilder.java
@@ -234,6 +234,10 @@ public class PreCompilerBuilder extends BaseBuilder {
// get the project objects
IProject project = getProject();
+
+ // Top level check to make sure the build can move forward.
+ abortOnBadSetup(project);
+
IJavaProject javaProject = JavaCore.create(project);
IAndroidTarget projectTarget = Sdk.getCurrent().getTarget(project);
@@ -284,10 +288,6 @@ public class PreCompilerBuilder extends BaseBuilder {
saveProjectBooleanProperty(PROPERTY_COMPILE_RESOURCES , mCompileResources);
// TODO also needs to store the list of aidl to compile/remove
- // At this point we have stored what needs to be build, so we can
- // do some high level test and abort if needed.
- abortOnBadSetup(project);
-
// if there was some XML errors, we just return w/o doing
// anything since we've put some markers in the files anyway.
if (dv != null && dv.mXmlError) {
@@ -381,7 +381,7 @@ public class PreCompilerBuilder extends BaseBuilder {
// mark the manifest file
String message = String.format(Messages.Package_s_Doesnt_Exist_Error,
mManifestPackage);
- BaseProjectHelper.addMarker(manifest, AndroidConstants.MARKER_AAPT, message,
+ BaseProjectHelper.addMarker(manifest, AndroidConstants.MARKER_AAPT_COMPILE, message,
IMarker.SEVERITY_ERROR);
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project, message);
@@ -409,8 +409,8 @@ public class PreCompilerBuilder extends BaseBuilder {
String osManifestPath = manifestLocation.toOSString();
// remove the aapt markers
- removeMarkersFromFile(manifest, AndroidConstants.MARKER_AAPT);
- removeMarkersFromContainer(resFolder, AndroidConstants.MARKER_AAPT);
+ removeMarkersFromFile(manifest, AndroidConstants.MARKER_AAPT_COMPILE);
+ removeMarkersFromContainer(resFolder, AndroidConstants.MARKER_AAPT_COMPILE);
AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, project,
Messages.Preparing_Generated_Files);
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/preferences/AndroidPreferencePage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/preferences/AndroidPreferencePage.java
index c27c106..458f78e 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/preferences/AndroidPreferencePage.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/preferences/AndroidPreferencePage.java
@@ -17,11 +17,19 @@
package com.android.ide.eclipse.adt.preferences;
import com.android.ide.eclipse.adt.AdtPlugin;
+import com.android.ide.eclipse.adt.sdk.Sdk;
+import com.android.ide.eclipse.adt.sdk.Sdk.ITargetChangeListener;
+import com.android.sdklib.IAndroidTarget;
+import com.android.sdkuilib.SdkTargetSelector;
+import org.eclipse.core.resources.IProject;
import org.eclipse.jface.preference.DirectoryFieldEditor;
import org.eclipse.jface.preference.FieldEditorPreferencePage;
import org.eclipse.jface.resource.JFaceResources;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPreferencePage;
@@ -80,6 +88,9 @@ public class AndroidPreferencePage extends FieldEditorPreferencePage implements
*/
private static class SdkDirectoryFieldEditor extends DirectoryFieldEditor {
+ private SdkTargetSelector mTargetSelector;
+ private TargetChangedListener mTargetChangeListener;
+
public SdkDirectoryFieldEditor(String name, String labelText, Composite parent) {
super(name, labelText, parent);
setEmptyStringAllowed(false);
@@ -131,5 +142,68 @@ public class AndroidPreferencePage extends FieldEditorPreferencePage implements
setValidateStrategy(VALIDATE_ON_KEY_STROKE);
return super.getTextControl(parent);
}
+
+ /* (non-Javadoc)
+ * Method declared on StringFieldEditor (and FieldEditor).
+ */
+ @Override
+ protected void doFillIntoGrid(Composite parent, int numColumns) {
+ super.doFillIntoGrid(parent, numColumns);
+
+ GridData gd;
+ Label l = new Label(parent, SWT.NONE);
+ l.setText("Note: The list of SDK Targets below is only reloaded once you hit 'Apply' or 'OK'.");
+ gd = new GridData(GridData.FILL_HORIZONTAL);
+ gd.horizontalSpan = numColumns;
+ l.setLayoutData(gd);
+
+ try {
+ // We may not have an sdk if the sdk path pref is empty or not valid.
+ Sdk sdk = Sdk.getCurrent();
+ IAndroidTarget[] targets = sdk != null ? sdk.getTargets() : null;
+
+ mTargetSelector = new SdkTargetSelector(parent,
+ targets,
+ false, /*allowSelection*/
+ false /*multipleSelection*/);
+ gd = (GridData) mTargetSelector.getLayoutData();
+ gd.horizontalSpan = numColumns;
+
+ if (mTargetChangeListener == null) {
+ mTargetChangeListener = new TargetChangedListener();
+ AdtPlugin.getDefault().addTargetListener(mTargetChangeListener);
+ }
+ } catch (Exception e) {
+ // We need to catch *any* exception that arises here, otherwise it disables
+ // the whole pref panel. We can live without the Sdk target selector but
+ // not being able to actually set an sdk path.
+ AdtPlugin.log(e, "SdkTargetSelector failed");
+ }
+ }
+
+ @Override
+ public void dispose() {
+ super.dispose();
+ if (mTargetChangeListener != null) {
+ AdtPlugin.getDefault().removeTargetListener(mTargetChangeListener);
+ mTargetChangeListener = null;
+ }
+ }
+
+ private class TargetChangedListener implements ITargetChangeListener {
+ public void onProjectTargetChange(IProject changedProject) {
+ // do nothing.
+ }
+
+ public void onTargetsLoaded() {
+ if (mTargetSelector != null) {
+ // We may not have an sdk if the sdk path pref is empty or not valid.
+ Sdk sdk = Sdk.getCurrent();
+ IAndroidTarget[] targets = sdk != null ? sdk.getTargets() : null;
+
+ mTargetSelector.setTargets(targets);
+ }
+ }
+ }
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainerInitializer.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainerInitializer.java
index 339dcd0..d686830 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainerInitializer.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainerInitializer.java
@@ -266,7 +266,6 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit
// We schedule a new job to put the marker after.
final String fmessage = markerMessage;
Job markerJob = new Job("Android SDK: Resolving error markers") {
- @SuppressWarnings("unchecked")
@Override
protected IStatus run(IProgressMonitor monitor) {
try {
@@ -296,7 +295,6 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit
// In some cases, the workspace may be locked for modification when we pass
// here, so we schedule a new job to put the marker after.
Job markerJob = new Job("Android SDK: Resolving error markers") {
- @SuppressWarnings("unchecked")
@Override
protected IStatus run(IProgressMonitor monitor) {
try {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/properties/AndroidPropertyPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/properties/AndroidPropertyPage.java
index 584dd0d..a4c019f 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/properties/AndroidPropertyPage.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/properties/AndroidPropertyPage.java
@@ -18,6 +18,7 @@ package com.android.ide.eclipse.adt.project.properties;
import com.android.ide.eclipse.adt.sdk.Sdk;
import com.android.sdklib.IAndroidTarget;
+import com.android.sdkuilib.ApkConfigWidget;
import com.android.sdkuilib.SdkTargetSelector;
import org.eclipse.core.resources.IProject;
@@ -32,6 +33,8 @@ import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.IWorkbenchPropertyPage;
import org.eclipse.ui.dialogs.PropertyPage;
+import java.util.Map;
+
/**
* Property page for "Android" project.
* This is accessible from the Package Explorer when right clicking a project and choosing
@@ -42,6 +45,7 @@ public class AndroidPropertyPage extends PropertyPage implements IWorkbenchPrope
private IProject mProject;
private SdkTargetSelector mSelector;
+ private ApkConfigWidget mApkConfigWidget;
public AndroidPropertyPage() {
// pass
@@ -51,28 +55,43 @@ public class AndroidPropertyPage extends PropertyPage implements IWorkbenchPrope
protected Control createContents(Composite parent) {
// get the element (this is not yet valid in the constructor).
mProject = (IProject)getElement();
-
- Composite top = new Composite(parent, SWT.NONE);
- top.setLayoutData(new GridData(GridData.FILL_BOTH));
- top.setLayout(new GridLayout(1, false));
- Label l = new Label(top, SWT.NONE);
- l.setText("Project Target");
-
// get the targets from the sdk
IAndroidTarget[] targets = null;
if (Sdk.getCurrent() != null) {
targets = Sdk.getCurrent().getTargets();
}
-
+
// build the UI.
+ Composite top = new Composite(parent, SWT.NONE);
+ top.setLayoutData(new GridData(GridData.FILL_BOTH));
+ top.setLayout(new GridLayout(1, false));
+
+ Label l = new Label(top, SWT.NONE);
+ l.setText("Project Target");
+
mSelector = new SdkTargetSelector(top, targets, false /*allowMultipleSelection*/);
- if (Sdk.getCurrent() != null) {
- IAndroidTarget target = Sdk.getCurrent().getTarget(mProject);
+ l = new Label(top, SWT.SEPARATOR | SWT.HORIZONTAL);
+ l.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+
+ l = new Label(top, SWT.NONE);
+ l.setText("Project APK Configurations");
+
+ mApkConfigWidget = new ApkConfigWidget(top);
+
+ // fill the ui
+ Sdk currentSdk = Sdk.getCurrent();
+ if (currentSdk != null && mProject.isOpen()) {
+ // get the target
+ IAndroidTarget target = currentSdk.getTarget(mProject);
if (target != null) {
mSelector.setSelection(target);
}
+
+ // get the apk configurations
+ Map<String, String> configs = currentSdk.getProjectApkConfigs(mProject);
+ mApkConfigWidget.fillTable(configs);
}
mSelector.setSelectionListener(new SelectionAdapter() {
@@ -83,14 +102,20 @@ public class AndroidPropertyPage extends PropertyPage implements IWorkbenchPrope
setValid(target != null);
}
});
+
+ if (mProject.isOpen() == false) {
+ // disable the ui.
+ }
return top;
}
@Override
public boolean performOk() {
- if (Sdk.getCurrent() != null) {
- Sdk.getCurrent().setProject(mProject, mSelector.getFirstSelected());
+ Sdk currentSdk = Sdk.getCurrent();
+ if (currentSdk != null) {
+ currentSdk.setProject(mProject, mSelector.getFirstSelected(),
+ mApkConfigWidget.getApkConfigs());
}
return true;
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetData.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetData.java
index 2309181..a8852e7 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetData.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetData.java
@@ -27,6 +27,7 @@ import com.android.ide.eclipse.editors.resources.manager.ProjectResources;
import com.android.ide.eclipse.editors.xml.descriptors.XmlDescriptors;
import com.android.layoutlib.api.ILayoutBridge;
import com.android.sdklib.IAndroidTarget;
+import com.android.sdklib.IAndroidTarget.IOptionalLibrary;
import java.util.Hashtable;
import java.util.Map;
@@ -43,6 +44,7 @@ public class AndroidTargetData {
public final static int DESCRIPTOR_RESOURCES = 5;
public final static int DESCRIPTOR_SEARCHABLE = 6;
public final static int DESCRIPTOR_PREFERENCES = 7;
+ public final static int DESCRIPTOR_GADGET_PROVIDER = 8;
public final static class LayoutBridge {
/** Link to the layout bridge */
@@ -51,6 +53,8 @@ public class AndroidTargetData {
public LoadStatus status = LoadStatus.LOADING;
public ClassLoader classLoader;
+
+ public int apiLevel;
}
private final IAndroidTarget mTarget;
@@ -93,6 +97,7 @@ public class AndroidTargetData {
/**
* Creates an AndroidTargetData object.
+ * @param optionalLibraries
*/
void setExtraData(IResourceRepository systemResourceRepository,
AndroidManifestDescriptors manifestDescriptors,
@@ -105,6 +110,7 @@ public class AndroidTargetData {
String[] broadcastIntentActionValues,
String[] serviceIntentActionValues,
String[] intentCategoryValues,
+ IOptionalLibrary[] optionalLibraries,
ProjectResources resources,
LayoutBridge layoutBridge) {
@@ -120,8 +126,9 @@ public class AndroidTargetData {
setPermissions(permissionValues);
setIntentFilterActionsAndCategories(activityIntentActionValues, broadcastIntentActionValues,
serviceIntentActionValues, intentCategoryValues);
+ setOptionalLibraries(optionalLibraries);
}
-
+
public DexWrapper getDexWrapper() {
return mDexWrapper;
}
@@ -151,6 +158,8 @@ public class AndroidTargetData {
return ResourcesDescriptors.getInstance();
case DESCRIPTOR_PREFERENCES:
return mXmlDescriptors.getPreferencesProvider();
+ case DESCRIPTOR_GADGET_PROVIDER:
+ return mXmlDescriptors.getGadgetProvider();
case DESCRIPTOR_SEARCHABLE:
return mXmlDescriptors.getSearchableProvider();
default :
@@ -283,6 +292,20 @@ public class AndroidTargetData {
setValues("(service,action,android:name)", serviceIntentActions); //$NON-NLS-1$
setValues("(category,android:name)", intentCategoryValues); //$NON-NLS-1$
}
+
+ private void setOptionalLibraries(IOptionalLibrary[] optionalLibraries) {
+ String[] values;
+
+ if (optionalLibraries == null) {
+ values = new String[0];
+ } else {
+ values = new String[optionalLibraries.length];
+ for (int i = 0; i < optionalLibraries.length; i++) {
+ values[i] = optionalLibraries[i].getName();
+ }
+ }
+ setValues("(uses-library,android:name)", values);
+ }
/**
* Sets a (name, values) pair in the hash map.
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetParser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetParser.java
index aab660d..04baeba 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetParser.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetParser.java
@@ -92,7 +92,7 @@ public final class AndroidTargetParser {
try {
SubMonitor progress = SubMonitor.convert(monitor,
String.format("Parsing SDK %1$s", mAndroidTarget.getName()),
- 200);
+ 14);
AndroidTargetData targetData = new AndroidTargetData(mAndroidTarget);
@@ -107,15 +107,14 @@ public final class AndroidTargetParser {
// we have loaded dx.
targetData.setDexWrapper(dexWrapper);
+ progress.worked(1);
// parse the rest of the data.
- progress.setWorkRemaining(120);
AndroidJarLoader classLoader =
new AndroidJarLoader(mAndroidTarget.getPath(IAndroidTarget.ANDROID_JAR));
preload(classLoader, progress.newChild(40, SubMonitor.SUPPRESS_NONE));
- progress.setWorkRemaining(80);
if (progress.isCanceled()) {
return Status.CANCEL_STATUS;
@@ -124,7 +123,7 @@ public final class AndroidTargetParser {
// get the resource Ids.
progress.subTask("Resource IDs");
IResourceRepository frameworkRepository = collectResourceIds(classLoader);
- progress.worked(5);
+ progress.worked(1);
if (progress.isCanceled()) {
return Status.CANCEL_STATUS;
@@ -133,7 +132,7 @@ public final class AndroidTargetParser {
// get the permissions
progress.subTask("Permissions");
String[] permissionValues = collectPermissions(classLoader);
- progress.worked(5);
+ progress.worked(1);
if (progress.isCanceled()) {
return Status.CANCEL_STATUS;
@@ -147,7 +146,7 @@ public final class AndroidTargetParser {
ArrayList<String> categories = new ArrayList<String>();
collectIntentFilterActionsAndCategories(activity_actions, broadcast_actions,
service_actions, categories);
- progress.worked(5);
+ progress.worked(1);
if (progress.isCanceled()) {
return Status.CANCEL_STATUS;
@@ -158,12 +157,14 @@ public final class AndroidTargetParser {
AttrsXmlParser attrsXmlParser = new AttrsXmlParser(
mAndroidTarget.getPath(IAndroidTarget.ATTRIBUTES));
attrsXmlParser.preload();
+ progress.worked(1);
progress.subTask("Manifest definitions");
AttrsXmlParser attrsManifestXmlParser = new AttrsXmlParser(
mAndroidTarget.getPath(IAndroidTarget.MANIFEST_ATTRIBUTES),
attrsXmlParser);
attrsManifestXmlParser.preload();
+ progress.worked(1);
Collection<ViewClassInfo> mainList = new ArrayList<ViewClassInfo>();
Collection<ViewClassInfo> groupList = new ArrayList<ViewClassInfo>();
@@ -171,7 +172,7 @@ public final class AndroidTargetParser {
// collect the layout/widgets classes
progress.subTask("Widgets and layouts");
collectLayoutClasses(classLoader, attrsXmlParser, mainList, groupList,
- progress.newChild(40));
+ progress.newChild(1));
if (progress.isCanceled()) {
return Status.CANCEL_STATUS;
@@ -185,7 +186,7 @@ public final class AndroidTargetParser {
mainList.clear();
groupList.clear();
collectPreferenceClasses(classLoader, attrsXmlParser, mainList, groupList,
- progress.newChild(5));
+ progress.newChild(1));
if (progress.isCanceled()) {
return Status.CANCEL_STATUS;
@@ -202,6 +203,11 @@ public final class AndroidTargetParser {
attrsManifestXmlParser);
Map<String, Map<String, Integer>> enumValueMap = attrsXmlParser.getEnumFlagValues();
+ Map<String, DeclareStyleableInfo> xmlGadgetMap = null;
+ if (mAndroidTarget.getApiVersionNumber() >= 3) {
+ xmlGadgetMap = collectGadgetDefinitions(attrsXmlParser);
+ }
+
if (progress.isCanceled()) {
return Status.CANCEL_STATUS;
}
@@ -210,7 +216,7 @@ public final class AndroidTargetParser {
// the PlatformData object.
AndroidManifestDescriptors manifestDescriptors = new AndroidManifestDescriptors();
manifestDescriptors.updateDescriptors(manifestMap);
- progress.worked(10);
+ progress.worked(1);
if (progress.isCanceled()) {
return Status.CANCEL_STATUS;
@@ -218,7 +224,7 @@ public final class AndroidTargetParser {
LayoutDescriptors layoutDescriptors = new LayoutDescriptors();
layoutDescriptors.updateDescriptors(layoutViewsInfo, layoutGroupsInfo);
- progress.worked(10);
+ progress.worked(1);
if (progress.isCanceled()) {
return Status.CANCEL_STATUS;
@@ -226,25 +232,28 @@ public final class AndroidTargetParser {
MenuDescriptors menuDescriptors = new MenuDescriptors();
menuDescriptors.updateDescriptors(xmlMenuMap);
- progress.worked(10);
+ progress.worked(1);
if (progress.isCanceled()) {
return Status.CANCEL_STATUS;
}
XmlDescriptors xmlDescriptors = new XmlDescriptors();
- xmlDescriptors.updateDescriptors(xmlSearchableMap, preferencesInfo,
+ xmlDescriptors.updateDescriptors(
+ xmlSearchableMap,
+ xmlGadgetMap,
+ preferencesInfo,
preferenceGroupsInfo);
- progress.worked(10);
+ progress.worked(1);
// load the framework resources.
ProjectResources resources = ResourceManager.getInstance().loadFrameworkResources(
mAndroidTarget);
- progress.worked(10);
+ progress.worked(1);
// now load the layout lib bridge
LayoutBridge layoutBridge = loadLayoutBridge();
- progress.worked(10);
+ progress.worked(1);
// and finally create the PlatformData with all that we loaded.
targetData.setExtraData(frameworkRepository,
@@ -258,6 +267,7 @@ public final class AndroidTargetParser {
broadcast_actions.toArray(new String[broadcast_actions.size()]),
service_actions.toArray(new String[service_actions.size()]),
categories.toArray(new String[categories.size()]),
+ mAndroidTarget.getOptionalLibraries(),
resources,
layoutBridge);
@@ -268,10 +278,6 @@ public final class AndroidTargetParser {
AdtPlugin.logAndPrintError(e, TAG, "SDK parser failed"); //$NON-NLS-1$
AdtPlugin.printToConsole("SDK parser failed", e.getMessage());
return new Status(IStatus.ERROR, AdtPlugin.PLUGIN_ID, "SDK parser failed", e);
- } finally {
- if (monitor != null) {
- monitor.done();
- }
}
}
@@ -605,6 +611,31 @@ public final class AndroidTargetParser {
}
/**
+ * Collects all gadgetProviderInfo definition information from the attrs.xml and returns it.
+ *
+ * @param attrsXmlParser The parser of the attrs.xml file
+ */
+ private Map<String, DeclareStyleableInfo> collectGadgetDefinitions(
+ AttrsXmlParser attrsXmlParser) {
+ Map<String, DeclareStyleableInfo> map = attrsXmlParser.getDeclareStyleableList();
+ Map<String, DeclareStyleableInfo> map2 = new HashMap<String, DeclareStyleableInfo>();
+ for (String key : new String[] { "GadgetProviderInfo" }) { //$NON-NLS-1$
+ if (map.containsKey(key)) {
+ map2.put(key, map.get(key));
+ } else {
+ AdtPlugin.log(IStatus.WARNING,
+ "Gadget declare-styleable %1$s not found in file %2$s", //$NON-NLS-1$
+ key, attrsXmlParser.getOsAttrsXmlPath());
+ AdtPlugin.printErrorToConsole("Android Framework Parser",
+ String.format("Gadget declare-styleable %1$s not found in file %2$s", //$NON-NLS-1$
+ key, attrsXmlParser.getOsAttrsXmlPath()));
+ }
+ }
+
+ return Collections.unmodifiableMap(map2);
+ }
+
+ /**
* Collects all manifest definition information from the attrs_manifest.xml and returns it.
*/
private Map<String, DeclareStyleableInfo> collectManifestDefinitions(
@@ -650,6 +681,15 @@ public final class AndroidTargetParser {
layoutBridge.status = LoadStatus.FAILED;
AdtPlugin.log(IStatus.ERROR, "Failed to load " + AndroidConstants.CLASS_BRIDGE); //$NON-NLS-1$
} else {
+ // get the api level
+ try {
+ layoutBridge.apiLevel = layoutBridge.bridge.getApiLevel();
+ } catch (AbstractMethodError e) {
+ // the first version of the api did not have this method
+ layoutBridge.apiLevel = 1;
+ }
+
+ // and mark the lib as loaded.
layoutBridge.status = LoadStatus.LOADED;
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/Sdk.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/Sdk.java
index c7773cc..ba0b568 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/Sdk.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/Sdk.java
@@ -18,6 +18,7 @@ package com.android.ide.eclipse.adt.sdk;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.project.internal.AndroidClasspathContainerInitializer;
+import com.android.ide.eclipse.adt.sdk.AndroidTargetData.LayoutBridge;
import com.android.ide.eclipse.editors.resources.manager.ResourceMonitor;
import com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IProjectListener;
import com.android.prefs.AndroidLocation.AndroidLocationException;
@@ -33,6 +34,7 @@ import com.android.sdklib.project.ProjectProperties.PropertyType;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
@@ -69,6 +71,22 @@ public class Sdk implements IProjectListener {
private final String mDocBaseUrl;
/**
+ * Classes implementing this interface will receive notification when targets are changed.
+ */
+ public interface ITargetChangeListener {
+ /**
+ * Sent when project has its target changed.
+ */
+ void onProjectTargetChange(IProject changedProject);
+
+ /**
+ * Called when the targets are loaded (either the SDK finished loading when Eclipse starts,
+ * or the SDK is changed).
+ */
+ void onTargetsLoaded();
+ }
+
+ /**
* Loads an SDK and returns an {@link Sdk} object if success.
* @param sdkLocation the OS path to the SDK.
*/
@@ -163,24 +181,87 @@ public class Sdk implements IProjectListener {
}
/**
- * Associates an {@link IProject} and an {@link IAndroidTarget}.
+ * Sets a new target and a new list of Apk configuration for a given project.
+ *
+ * @param project the project to receive the new apk configurations
+ * @param target The new target to set, or <code>null</code> to not change the current target.
+ * @param apkConfigMap a map of apk configurations. The map contains (name, filter) where name
+ * is the name of the configuration (a-zA-Z0-9 only), and filter is the comma separated list of
+ * resource configuration to include in the apk (see aapt -c). Can be <code>null</code> if the
+ * apk configurations should not be updated.
*/
- public void setProject(IProject project, IAndroidTarget target) {
+ public void setProject(IProject project, IAndroidTarget target,
+ Map<String, String> apkConfigMap) {
synchronized (mProjectTargetMap) {
- // look for the current target of the project
- IAndroidTarget previousTarget = mProjectTargetMap.get(project);
+ boolean resolveProject = false;
+ boolean compileProject = false;
+ boolean cleanProject = false;
+
+ ProjectProperties properties = ProjectProperties.load(
+ project.getLocation().toOSString(), PropertyType.DEFAULT);
+ if (properties == null) {
+ // doesn't exist yet? we create it.
+ properties = ProjectProperties.create(project.getLocation().toOSString(),
+ PropertyType.DEFAULT);
+ }
+
+ if (target != null) {
+ // look for the current target of the project
+ IAndroidTarget previousTarget = mProjectTargetMap.get(project);
+
+ if (target != previousTarget) {
+ // save the target hash string in the project persistent property
+ properties.setAndroidTarget(target);
+
+ // put it in a local map for easy access.
+ mProjectTargetMap.put(project, target);
+
+ resolveProject = true;
+ }
+ }
- if (target != previousTarget) {
- // save the target hash string in the project persistent property
- setProjectTargetHashString(project, target.hashString());
-
+ if (apkConfigMap != null) {
+ // save the apk configs in the project persistent property
+ cleanProject = ApkConfigurationHelper.setConfigs(properties, apkConfigMap);
+
// put it in a local map for easy access.
- mProjectTargetMap.put(project, target);
+ mProjectApkConfigMap.put(project, apkConfigMap);
+
+ compileProject = true;
+ }
- // recompile the project if needed.
+ // we are done with the modification. Save the property file.
+ try {
+ properties.save();
+ } catch (IOException e) {
+ AdtPlugin.log(e, "Failed to save default.properties for project '%s'",
+ project.getName());
+ }
+
+ if (resolveProject) {
+ // force a resolve of the project by updating the classpath container.
IJavaProject javaProject = JavaCore.create(project);
AndroidClasspathContainerInitializer.updateProjects(
new IJavaProject[] { javaProject });
+ } else if (compileProject) {
+ // If there was removed configs, we clean instead of build
+ // (to remove the obsolete ap_ and apk file from removed configs).
+ try {
+ project.build(cleanProject ?
+ IncrementalProjectBuilder.CLEAN_BUILD :
+ IncrementalProjectBuilder.FULL_BUILD,
+ null);
+ } catch (CoreException e) {
+ // failed to build? force resolve instead.
+ IJavaProject javaProject = JavaCore.create(project);
+ AndroidClasspathContainerInitializer.updateProjects(
+ new IJavaProject[] { javaProject });
+ }
+ }
+
+ // finally, update the opened editors.
+ if (resolveProject) {
+ AdtPlugin.getDefault().updateTargetListener(project);
}
}
}
@@ -218,7 +299,12 @@ public class Sdk implements IProjectListener {
*/
private static String loadProjectProperties(IProject project, Sdk sdkStorage) {
// load the default.properties from the project folder.
- ProjectProperties properties = ProjectProperties.load(project.getLocation().toOSString(),
+ IPath location = project.getLocation();
+ if (location == null) { // can return null when the project is being deleted.
+ // do nothing and return null;
+ return null;
+ }
+ ProjectProperties properties = ProjectProperties.load(location.toOSString(),
PropertyType.DEFAULT);
if (properties == null) {
AdtPlugin.log(IStatus.ERROR, "Failed to load properties file for project '%s'",
@@ -229,7 +315,7 @@ public class Sdk implements IProjectListener {
if (sdkStorage != null) {
Map<String, String> configMap = ApkConfigurationHelper.getConfigs(properties);
- if (configMap.size() > 0) {
+ if (configMap != null) {
sdkStorage.mProjectApkConfigMap.put(project, configMap);
}
}
@@ -296,40 +382,6 @@ public class Sdk implements IProjectListener {
return mProjectApkConfigMap.get(project);
}
- public void setProjectApkConfigs(IProject project, Map<String, String> configMap)
- throws CoreException {
- // first set the new map
- mProjectApkConfigMap.put(project, configMap);
-
- // Now we write this in default.properties.
- // Because we don't want to erase other properties from default.properties, we first load
- // them
- ProjectProperties properties = ProjectProperties.load(project.getLocation().toOSString(),
- PropertyType.DEFAULT);
- if (properties == null) {
- // doesn't exist yet? we create it.
- properties = ProjectProperties.create(project.getLocation().toOSString(),
- PropertyType.DEFAULT);
- }
-
- // sets the configs in the property file.
- boolean hasRemovedConfig = ApkConfigurationHelper.setConfigs(properties, configMap);
-
- // and rewrite the file.
- try {
- properties.save();
- } catch (IOException e) {
- AdtPlugin.log(e, "Failed to save default.properties for project '%s'",
- project.getName());
- }
-
- // we're done, force a rebuild. If there was removed config, we clean instead of build
- // (to remove the obsolete ap_ and apk file from removed configs).
- project.build(hasRemovedConfig ?
- IncrementalProjectBuilder.CLEAN_BUILD : IncrementalProjectBuilder.FULL_BUILD,
- null);
- }
-
/**
* Returns the {@link AvdManager}. If the AvdManager failed to parse the AVD folder, this could
* be <code>null</code>.
@@ -402,8 +454,24 @@ public class Sdk implements IProjectListener {
}
public void projectClosed(IProject project) {
- mProjectTargetMap.remove(project);
- mProjectApkConfigMap.remove(project);
+ // get the target project
+ synchronized (mProjectTargetMap) {
+ IAndroidTarget target = mProjectTargetMap.get(project);
+ if (target != null) {
+ // get the bridge for the target, and clear the cache for this project.
+ AndroidTargetData data = mTargetDataMap.get(target);
+ if (data != null) {
+ LayoutBridge bridge = data.getLayoutBridge();
+ if (bridge != null && bridge.status == LoadStatus.LOADED) {
+ bridge.bridge.clearCaches(project);
+ }
+ }
+ }
+
+ // now remove the project for the maps.
+ mProjectTargetMap.remove(project);
+ mProjectApkConfigMap.remove(project);
+ }
}
public void projectDeleted(IProject project) {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/actions/NewProjectAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/actions/NewProjectAction.java
new file mode 100644
index 0000000..e0d0d5e
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/actions/NewProjectAction.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/org/documents/epl-v10.php
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ide.eclipse.adt.wizards.actions;
+
+import com.android.ide.eclipse.adt.wizards.newproject.NewProjectWizard;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.ui.IWorkbenchWizard;
+
+/**
+ * Delegate for the toolbar action "Android Project".
+ * It displays the Android New Project wizard.
+ */
+public class NewProjectAction extends OpenWizardAction {
+
+ @Override
+ protected IWorkbenchWizard instanciateWizard(IAction action) {
+ return new NewProjectWizard();
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/actions/NewXmlFileAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/actions/NewXmlFileAction.java
new file mode 100644
index 0000000..8c4a115
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/actions/NewXmlFileAction.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/org/documents/epl-v10.php
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ide.eclipse.adt.wizards.actions;
+
+import com.android.ide.eclipse.editors.wizards.NewXmlFileWizard;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.ui.IWorkbenchWizard;
+
+/**
+ * Delegate for the toolbar action "Android Project".
+ * It displays the Android New XML file wizard.
+ */
+public class NewXmlFileAction extends OpenWizardAction {
+
+ @Override
+ protected IWorkbenchWizard instanciateWizard(IAction action) {
+ return new NewXmlFileWizard();
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/actions/OpenWizardAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/actions/OpenWizardAction.java
new file mode 100644
index 0000000..4fc9dee
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/actions/OpenWizardAction.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/org/documents/epl-v10.php
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ide.eclipse.adt.wizards.actions;
+
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.jface.viewers.StructuredSelection;
+import org.eclipse.jface.wizard.WizardDialog;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IEditorInput;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkbenchWindowActionDelegate;
+import org.eclipse.ui.IWorkbenchWizard;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
+import org.eclipse.ui.internal.LegacyResourceSupport;
+import org.eclipse.ui.internal.actions.NewWizardShortcutAction;
+import org.eclipse.ui.internal.util.Util;
+
+/**
+ * An abstract action that displays one of our wizards.
+ * Derived classes must provide the actual wizard to display.
+ */
+/*package*/ abstract class OpenWizardAction implements IWorkbenchWindowActionDelegate {
+
+ /**
+ * The wizard dialog width, extracted from {@link NewWizardShortcutAction}
+ */
+ private static final int SIZING_WIZARD_WIDTH = 500;
+
+ /**
+ * The wizard dialog height, extracted from {@link NewWizardShortcutAction}
+ */
+ private static final int SIZING_WIZARD_HEIGHT = 500;
+
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.IWorkbenchWindowActionDelegate#dispose()
+ */
+ public void dispose() {
+ // pass
+ }
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.IWorkbenchWindowActionDelegate#init(org.eclipse.ui.IWorkbenchWindow)
+ */
+ public void init(IWorkbenchWindow window) {
+ // pass
+ }
+
+ /**
+ * Opens and display the Android New Project Wizard.
+ * <p/>
+ * Most of this implementation is extracted from {@link NewWizardShortcutAction#run()}.
+ *
+ * @see org.eclipse.ui.IActionDelegate#run(org.eclipse.jface.action.IAction)
+ */
+ public void run(IAction action) {
+
+ // get the workbench and the current window
+ IWorkbench workbench = PlatformUI.getWorkbench();
+ IWorkbenchWindow window = workbench.getActiveWorkbenchWindow();
+
+ // This code from NewWizardShortcutAction#run() gets the current window selection
+ // and converts it to a workbench structured selection for the wizard, if possible.
+ ISelection selection = window.getSelectionService().getSelection();
+ IStructuredSelection selectionToPass = StructuredSelection.EMPTY;
+ if (selection instanceof IStructuredSelection) {
+ selectionToPass = (IStructuredSelection) selection;
+ } else {
+ // Build the selection from the IFile of the editor
+ IWorkbenchPart part = window.getPartService().getActivePart();
+ if (part instanceof IEditorPart) {
+ IEditorInput input = ((IEditorPart) part).getEditorInput();
+ Class<?> fileClass = LegacyResourceSupport.getFileClass();
+ if (input != null && fileClass != null) {
+ Object file = Util.getAdapter(input, fileClass);
+ if (file != null) {
+ selectionToPass = new StructuredSelection(file);
+ }
+ }
+ }
+ }
+
+ // Create the wizard and initialize it with the selection
+ IWorkbenchWizard wizard = instanciateWizard(action);
+ wizard.init(workbench, selectionToPass);
+
+ // It's not visible yet until a dialog is created and opened
+ Shell parent = window.getShell();
+ WizardDialog dialog = new WizardDialog(parent, wizard);
+ dialog.create();
+
+ // This code comes straight from NewWizardShortcutAction#run()
+ Point defaultSize = dialog.getShell().getSize();
+ dialog.getShell().setSize(
+ Math.max(SIZING_WIZARD_WIDTH, defaultSize.x),
+ Math.max(SIZING_WIZARD_HEIGHT, defaultSize.y));
+ window.getWorkbench().getHelpSystem().setHelp(dialog.getShell(),
+ IWorkbenchHelpContextIds.NEW_WIZARD_SHORTCUT);
+
+ dialog.open();
+ }
+
+ /**
+ * Called by {@link #run(IAction)} to instantiate the actual wizard.
+ *
+ * @param action The action parameter from {@link #run(IAction)}.
+ * @return A new wizard instance. Must not be null.
+ */
+ protected abstract IWorkbenchWizard instanciateWizard(IAction action);
+
+ /* (non-Javadoc)
+ * @see org.eclipse.ui.IActionDelegate#selectionChanged(org.eclipse.jface.action.IAction, org.eclipse.jface.viewers.ISelection)
+ */
+ public void selectionChanged(IAction action, ISelection selection) {
+ // pass
+ }
+
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectWizard.java
index 607159a..cb79796 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectWizard.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectWizard.java
@@ -105,6 +105,8 @@ public class NewProjectWizard extends Wizard implements INewWizard {
SdkConstants.FD_LAYOUT + AndroidConstants.WS_SEP;
private static final String VALUES_DIRECTORY =
SdkConstants.FD_VALUES + AndroidConstants.WS_SEP;
+ private static final String GEN_SRC_DIRECTORY =
+ SdkConstants.FD_GEN_SOURCES + AndroidConstants.WS_SEP;
private static final String TEMPLATES_DIRECTORY = "templates/"; //$NON-NLS-1$
private static final String TEMPLATE_MANIFEST = TEMPLATES_DIRECTORY
@@ -114,7 +116,7 @@ public class NewProjectWizard extends Wizard implements INewWizard {
private static final String TEMPLATE_USES_SDK = TEMPLATES_DIRECTORY
+ "uses-sdk.template"; //$NON-NLS-1$
private static final String TEMPLATE_INTENT_LAUNCHER = TEMPLATES_DIRECTORY
- + "launcher_intent_filter.template"; //$NON-NLS-1$
+ + "launcher_intent_filter.template"; //$NON-NLS-1$
private static final String TEMPLATE_STRINGS = TEMPLATES_DIRECTORY
+ "strings.template"; //$NON-NLS-1$
@@ -341,15 +343,20 @@ public class NewProjectWizard extends Wizard implements INewWizard {
// Create folders in the project if they don't already exist
addDefaultDirectories(project, AndroidConstants.WS_ROOT, DEFAULT_DIRECTORIES, monitor);
- String[] sourceFolder = new String[] { (String) parameters.get(PARAM_SRC_FOLDER) };
- addDefaultDirectories(project, AndroidConstants.WS_ROOT, sourceFolder, monitor);
+ String[] sourceFolders = new String[] {
+ (String) parameters.get(PARAM_SRC_FOLDER),
+ GEN_SRC_DIRECTORY
+ };
+ addDefaultDirectories(project, AndroidConstants.WS_ROOT, sourceFolders, monitor);
// Create the resource folders in the project if they don't already exist.
addDefaultDirectories(project, RES_DIRECTORY, RES_DIRECTORIES, monitor);
// Setup class path
IJavaProject javaProject = JavaCore.create(project);
- setupSourceFolder(javaProject, sourceFolder[0], monitor);
+ for (String sourceFolder : sourceFolders) {
+ setupSourceFolder(javaProject, sourceFolder, monitor);
+ }
if (((Boolean) parameters.get(PARAM_IS_NEW_PROJECT)).booleanValue()) {
// Create files in the project if they don't already exist
@@ -359,7 +366,7 @@ public class NewProjectWizard extends Wizard implements INewWizard {
addIcon(project, monitor);
// Create the default package components
- addSampleCode(project, sourceFolder[0], parameters, stringDictionary, monitor);
+ addSampleCode(project, sourceFolders[0], parameters, stringDictionary, monitor);
// add the string definition file if needed
if (stringDictionary.size() > 0) {
@@ -371,7 +378,8 @@ public class NewProjectWizard extends Wizard implements INewWizard {
monitor);
}
- Sdk.getCurrent().setProject(project, (IAndroidTarget) parameters.get(PARAM_SDK_TARGET));
+ Sdk.getCurrent().setProject(project, (IAndroidTarget) parameters.get(PARAM_SDK_TARGET),
+ null /* apkConfigMap*/);
// Fix the project to make sure all properties are as expected.
// Necessary for existing projects and good for new ones to.
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/AndroidConstants.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/AndroidConstants.java
index b1c57a6..e201132 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/AndroidConstants.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/AndroidConstants.java
@@ -148,8 +148,11 @@ public class AndroidConstants {
/** The old common plug-in ID. Please do not use for new features. */
public static final String COMMON_PLUGIN_ID = "com.android.ide.eclipse.common"; //$NON-NLS-1$
- /** aapt marker error. */
- public final static String MARKER_AAPT = COMMON_PLUGIN_ID + ".aaptProblem"; //$NON-NLS-1$
+ /** aapt marker error when running the compile command */
+ public final static String MARKER_AAPT_COMPILE = COMMON_PLUGIN_ID + ".aaptProblem"; //$NON-NLS-1$
+
+ /** aapt marker error when running the package command */
+ public final static String MARKER_AAPT_PACKAGE = COMMON_PLUGIN_ID + ".aapt2Problem"; //$NON-NLS-1$
/** XML marker error. */
public final static String MARKER_XML = COMMON_PLUGIN_ID + ".xmlProblem"; //$NON-NLS-1$
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/AndroidEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/AndroidEditor.java
index dca7db0..c7541e9 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/AndroidEditor.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/AndroidEditor.java
@@ -19,6 +19,7 @@ package com.android.ide.eclipse.editors;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.sdk.AndroidTargetData;
import com.android.ide.eclipse.adt.sdk.Sdk;
+import com.android.ide.eclipse.adt.sdk.Sdk.ITargetChangeListener;
import com.android.ide.eclipse.editors.uimodel.UiElementNode;
import com.android.sdklib.IAndroidTarget;
@@ -97,8 +98,9 @@ public abstract class AndroidEditor extends FormEditor implements IResourceChang
private StructuredTextEditor mTextEditor;
/** Listener for the XML model from the StructuredEditor */
private XmlModelStateListener mXmlModelStateListener;
- /** Listener to update the root node if the resource framework changes */
- private Runnable mResourceRefreshListener;
+ /** Listener to update the root node if the target of the file is changed because of a
+ * SDK location change or a project target change */
+ private ITargetChangeListener mTargetListener;
/**
* Creates a form editor.
@@ -107,15 +109,21 @@ public abstract class AndroidEditor extends FormEditor implements IResourceChang
super();
ResourcesPlugin.getWorkspace().addResourceChangeListener(this);
- mResourceRefreshListener = new Runnable() {
- public void run() {
- commitPages(false /* onSave */);
+ mTargetListener = new ITargetChangeListener() {
+ public void onProjectTargetChange(IProject changedProject) {
+ if (changedProject == getProject()) {
+ onTargetsLoaded();
+ }
+ }
+ public void onTargetsLoaded() {
+ commitPages(false /* onSave */);
+
// recreate the ui root node always
initUiRootNode(true /*force*/);
}
};
- AdtPlugin.getDefault().addResourceChangedListener(mResourceRefreshListener);
+ AdtPlugin.getDefault().addTargetListener(mTargetListener);
}
// ---- Abstract Methods ----
@@ -340,9 +348,9 @@ public abstract class AndroidEditor extends FormEditor implements IResourceChang
}
ResourcesPlugin.getWorkspace().removeResourceChangeListener(this);
- if (mResourceRefreshListener != null) {
- AdtPlugin.getDefault().removeResourceChangedListener(mResourceRefreshListener);
- mResourceRefreshListener = null;
+ if (mTargetListener != null) {
+ AdtPlugin.getDefault().removeTargetListener(mTargetListener);
+ mTargetListener = null;
}
super.dispose();
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/DescriptorsUtils.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/DescriptorsUtils.java
index cc923bf..f1d62a1 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/DescriptorsUtils.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/descriptors/DescriptorsUtils.java
@@ -313,7 +313,7 @@ public final class DescriptorsUtils {
*
* @param attributes The list of {@link AttributeDescriptor} to compare to.
* @param nsUri The URI of the attribute. Can be null if attribute has no namespace.
- * See {@link AndroidConstants#NS_RESOURCES} for a common value.
+ * See {@link SdkConstants#NS_RESOURCES} for a common value.
* @param info The {@link AttributeInfo} to know whether it is included in the above list.
* @return True if this {@link AttributeInfo} is already present in
* the {@link AttributeDescriptor} list.
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/GraphicalLayoutEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/GraphicalLayoutEditor.java
index ca7cac5..eb7dee6 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/GraphicalLayoutEditor.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/GraphicalLayoutEditor.java
@@ -21,6 +21,7 @@ import com.android.ide.eclipse.adt.sdk.AndroidTargetData;
import com.android.ide.eclipse.adt.sdk.LoadStatus;
import com.android.ide.eclipse.adt.sdk.Sdk;
import com.android.ide.eclipse.adt.sdk.AndroidTargetData.LayoutBridge;
+import com.android.ide.eclipse.adt.sdk.Sdk.ITargetChangeListener;
import com.android.ide.eclipse.common.resources.ResourceType;
import com.android.ide.eclipse.editors.IconFactory;
import com.android.ide.eclipse.editors.layout.LayoutEditor.UiEditorActions;
@@ -198,13 +199,21 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
private ProjectCallback mProjectCallback;
private ILayoutLog mLogger;
+ private boolean mNeedsXmlReload = false;
private boolean mNeedsRecompute = false;
private int mPlatformThemeCount = 0;
private boolean mDisableUpdates = false;
- private boolean mActive = false;
- private Runnable mFrameworkResourceChangeListener = new Runnable() {
- public void run() {
+ /** Listener to update the root node if the target of the file is changed because of a
+ * SDK location change or a project target change */
+ private ITargetChangeListener mTargetListener = new ITargetChangeListener() {
+ public void onProjectTargetChange(IProject changedProject) {
+ if (changedProject == getLayoutEditor().getProject()) {
+ onTargetsLoaded();
+ }
+ }
+
+ public void onTargetsLoaded() {
// because the SDK changed we must reset the configured framework resource.
mConfiguredFrameworkRes = null;
@@ -228,7 +237,7 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
private final Runnable mConditionalRecomputeRunnable = new Runnable() {
public void run() {
- if (mActive) {
+ if (mLayoutEditor.isGraphicalEditorActive()) {
recomputeLayout();
} else {
mNeedsRecompute = true;
@@ -253,7 +262,7 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
mMatchImage = factory.getIcon("match"); //$NON-NLS-1$
mErrorImage = factory.getIcon("error"); //$NON-NLS-1$
- AdtPlugin.getDefault().addResourceChangedListener(mFrameworkResourceChangeListener);
+ AdtPlugin.getDefault().addTargetListener(mTargetListener);
}
// ------------------------------------
@@ -561,10 +570,9 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
@Override
public void dispose() {
- if (mFrameworkResourceChangeListener != null) {
- AdtPlugin.getDefault().removeResourceChangedListener(
- mFrameworkResourceChangeListener);
- mFrameworkResourceChangeListener = null;
+ if (mTargetListener != null) {
+ AdtPlugin.getDefault().removeTargetListener(mTargetListener);
+ mTargetListener = null;
}
LayoutReloadMonitor.getMonitor().removeListener(mEditedFile.getProject(), this);
@@ -1026,25 +1034,36 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
}
/**
- * Update the layout editor when the Xml model is changed.
+ * Callback for XML model changed. Only update/recompute the layout if the editor is visible
*/
void onXmlModelChanged() {
- GraphicalViewer viewer = getGraphicalViewer();
-
- // try to preserve the selection before changing the content
- SelectionManager selMan = viewer.getSelectionManager();
- ISelection selection = selMan.getSelection();
-
- try {
- viewer.setContents(getModel());
- } finally {
- selMan.setSelection(selection);
- }
-
if (mLayoutEditor.isGraphicalEditorActive()) {
+ doXmlReload(true /* force */);
recomputeLayout();
} else {
- mNeedsRecompute = true;
+ mNeedsXmlReload = true;
+ }
+ }
+
+ /**
+ * Actually performs the XML reload
+ * @see #onXmlModelChanged()
+ */
+ private void doXmlReload(boolean force) {
+ if (force || mNeedsXmlReload) {
+ GraphicalViewer viewer = getGraphicalViewer();
+
+ // try to preserve the selection before changing the content
+ SelectionManager selMan = viewer.getSelectionManager();
+ ISelection selection = selMan.getSelection();
+
+ try {
+ viewer.setContents(getModel());
+ } finally {
+ selMan.setSelection(selection);
+ }
+
+ mNeedsXmlReload = false;
}
}
@@ -1648,7 +1667,9 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
/**
* Recomputes the layout with the help of layoutlib.
*/
+ @SuppressWarnings("deprecation")
void recomputeLayout() {
+ doXmlReload(false /* force */);
try {
// check that the resource exists. If the file is opened but the project is closed
// or deleted for some reason (changed from outside of eclipse), then this will
@@ -1763,20 +1784,47 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
if (themeIndex != -1) {
String theme = mThemeCombo.getItem(themeIndex);
- // change the string if it's a custom theme to make sure we can
- // differentiate them
- if (themeIndex >= mPlatformThemeCount) {
- theme = "*" + theme; //$NON-NLS-1$
- }
-
// Compute the layout
UiElementPullParser parser = new UiElementPullParser(getModel());
Rectangle rect = getBounds();
- ILayoutResult result = bridge.bridge.computeLayout(parser,
- iProject /* projectKey */,
- rect.width, rect.height, theme,
- mConfiguredProjectRes, frameworkResources, mProjectCallback,
- mLogger);
+ ILayoutResult result = null;
+ if (bridge.apiLevel >= 3) {
+ // call the new api with proper theme differentiator and
+ // density/dpi support.
+ boolean isProjectTheme = themeIndex >= mPlatformThemeCount;
+
+ // FIXME pass the density/dpi from somewhere (resource config or skin).
+ result = bridge.bridge.computeLayout(parser,
+ iProject /* projectKey */,
+ rect.width, rect.height, 160, 160.f, 160.f,
+ theme, isProjectTheme,
+ mConfiguredProjectRes, frameworkResources, mProjectCallback,
+ mLogger);
+ } else if (bridge.apiLevel == 2) {
+ // api with boolean for separation of project/framework theme
+ boolean isProjectTheme = themeIndex >= mPlatformThemeCount;
+
+ result = bridge.bridge.computeLayout(parser,
+ iProject /* projectKey */,
+ rect.width, rect.height, theme, isProjectTheme,
+ mConfiguredProjectRes, frameworkResources, mProjectCallback,
+ mLogger);
+ } else {
+ // oldest api with no density/dpi, and project theme boolean mixed
+ // into the theme name.
+
+ // change the string if it's a custom theme to make sure we can
+ // differentiate them
+ if (themeIndex >= mPlatformThemeCount) {
+ theme = "*" + theme; //$NON-NLS-1$
+ }
+
+ result = bridge.bridge.computeLayout(parser,
+ iProject /* projectKey */,
+ rect.width, rect.height, theme,
+ mConfiguredProjectRes, frameworkResources, mProjectCallback,
+ mLogger);
+ }
// update the UiElementNode with the layout info.
if (result.getSuccess() == ILayoutResult.SUCCESS) {
@@ -1921,8 +1969,7 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
* Responds to a page change that made the Graphical editor page the activated page.
*/
void activated() {
- mActive = true;
- if (mNeedsRecompute) {
+ if (mNeedsRecompute || mNeedsXmlReload) {
recomputeLayout();
}
}
@@ -1931,7 +1978,7 @@ public class GraphicalLayoutEditor extends GraphicalEditorWithPalette
* Responds to a page change that made the Graphical editor page the deactivated page
*/
void deactivated() {
- mActive = false;
+ // nothing to be done here for now.
}
/**
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutEditor.java
index 880ee2b..dabe797 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutEditor.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutEditor.java
@@ -269,8 +269,12 @@ public class LayoutEditor extends AndroidEditor implements IShowEditorInput, IPa
protected void pageChange(int newPageIndex) {
super.pageChange(newPageIndex);
- if (mGraphicalEditor != null && newPageIndex == mGraphicalEditorIndex) {
- mGraphicalEditor.activated();
+ if (mGraphicalEditor != null) {
+ if (newPageIndex == mGraphicalEditorIndex) {
+ mGraphicalEditor.activated();
+ } else {
+ mGraphicalEditor.deactivated();
+ }
}
}
@@ -278,8 +282,12 @@ public class LayoutEditor extends AndroidEditor implements IShowEditorInput, IPa
public void partActivated(IWorkbenchPart part) {
if (part == this) {
- if (mGraphicalEditor != null && getActivePage() == mGraphicalEditorIndex) {
- mGraphicalEditor.activated();
+ if (mGraphicalEditor != null) {
+ if (getActivePage() == mGraphicalEditorIndex) {
+ mGraphicalEditor.activated();
+ } else {
+ mGraphicalEditor.deactivated();
+ }
}
}
}
@@ -334,23 +342,23 @@ public class LayoutEditor extends AndroidEditor implements IShowEditorInput, IPa
// ---- Local Methods ----
/**
- * Returns true if the Graphics editor page is visible.
- * This <b>must</b> be called from the UI thread.
+ * Returns true if the Graphics editor page is visible. This <b>must</b> be
+ * called from the UI thread.
*/
boolean isGraphicalEditorActive() {
IWorkbenchPartSite workbenchSite = getSite();
IWorkbenchPage workbenchPage = workbenchSite.getPage();
-
+
// check if the editor is visible in the workbench page
- if (workbenchPage.isPartVisible(this)) {
+ if (workbenchPage.isPartVisible(this) && workbenchPage.getActiveEditor() == this) {
// and then if the page of the editor is visible (not to be confused with
// the workbench page)
return mGraphicalEditorIndex == getActivePage();
}
-
- return false;
- }
+ return false;
+ }
+
@Override
protected void initUiRootNode(boolean force) {
// The root UI node is always created, even if there's no corresponding XML node.
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/AndroidManifestDescriptors.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/AndroidManifestDescriptors.java
index 61b73a2..77c08b5 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/AndroidManifestDescriptors.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/AndroidManifestDescriptors.java
@@ -195,6 +195,8 @@ public final class AndroidManifestDescriptors implements IDescriptorProvider {
overrides.put("*/permission", ListAttributeDescriptor.class); //$NON-NLS-1$
overrides.put("*/targetPackage", PackageAttributeDescriptor.class); //$NON-NLS-1$
+ overrides.put("uses-library/name", ListAttributeDescriptor.class); //$NON-NLS-1$
+
overrides.put("action,category,uses-permission/" + ANDROID_NAME_ATTR, //$NON-NLS-1$
ListAttributeDescriptor.class);
overrides.put("application/" + ANDROID_NAME_ATTR, ApplicationAttributeDescriptor.class); //$NON-NLS-1$
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ClassAttributeDescriptor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ClassAttributeDescriptor.java
index abaf438..629b37c 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ClassAttributeDescriptor.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/descriptors/ClassAttributeDescriptor.java
@@ -16,12 +16,12 @@
package com.android.ide.eclipse.editors.manifest.descriptors;
-import com.android.ide.eclipse.common.AndroidConstants;
import com.android.ide.eclipse.editors.descriptors.TextAttributeDescriptor;
import com.android.ide.eclipse.editors.manifest.model.UiClassAttributeNode;
import com.android.ide.eclipse.editors.manifest.model.UiClassAttributeNode.IPostTypeCreationAction;
import com.android.ide.eclipse.editors.uimodel.UiAttributeNode;
import com.android.ide.eclipse.editors.uimodel.UiElementNode;
+import com.android.sdklib.SdkConstants;
/**
* Describes an XML attribute representing a class name.
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/UiTreeBlock.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/UiTreeBlock.java
index e3255d9..fc384e8 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/UiTreeBlock.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/ui/tree/UiTreeBlock.java
@@ -17,6 +17,7 @@
package com.android.ide.eclipse.editors.ui.tree;
import com.android.ide.eclipse.adt.AdtPlugin;
+import com.android.ide.eclipse.adt.sdk.Sdk.ITargetChangeListener;
import com.android.ide.eclipse.editors.AndroidEditor;
import com.android.ide.eclipse.editors.IconFactory;
import com.android.ide.eclipse.editors.descriptors.ElementDescriptor;
@@ -26,6 +27,7 @@ import com.android.ide.eclipse.editors.uimodel.IUiUpdateListener;
import com.android.ide.eclipse.editors.uimodel.UiDocumentNode;
import com.android.ide.eclipse.editors.uimodel.UiElementNode;
+import org.eclipse.core.resources.IProject;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
@@ -285,13 +287,21 @@ public final class UiTreeBlock extends MasterDetailsBlock implements ICommitXml
}
};
- final Runnable resourceRefreshListener = new Runnable() {
- public void run() {
+ /** Listener to update the root node if the target of the file is changed because of a
+ * SDK location change or a project target change */
+ final ITargetChangeListener targetListener = new ITargetChangeListener() {
+ public void onProjectTargetChange(IProject changedProject) {
+ if (changedProject == mEditor.getProject()) {
+ onTargetsLoaded();
+ }
+ }
+
+ public void onTargetsLoaded() {
// If a details part has been created, we need to "refresh" it too.
if (mDetailsPart != null) {
// The details part does not directly expose access to its internal
// page book. Instead it is possible to resize the page book to 0 and then
- // back to its original value, which as the side effect of removing all
+ // back to its original value, which has the side effect of removing all
// existing cached pages.
int limit = mDetailsPart.getPageLimit();
mDetailsPart.setPageLimit(0);
@@ -306,7 +316,7 @@ public final class UiTreeBlock extends MasterDetailsBlock implements ICommitXml
changeRootAndDescriptors(mUiRootNode, mDescriptorFilters, false /* refresh */);
// Listen on resource framework changes to refresh the tree
- AdtPlugin.getDefault().addResourceChangedListener(resourceRefreshListener);
+ AdtPlugin.getDefault().addTargetListener(targetListener);
// Remove listeners when the tree widget gets disposed.
tree.addDisposeListener(new DisposeListener() {
@@ -318,7 +328,7 @@ public final class UiTreeBlock extends MasterDetailsBlock implements ICommitXml
node.removeUpdateListener(mUiRefreshListener);
mUiRootNode.removeUpdateListener(mUiEnableListener);
- AdtPlugin.getDefault().removeResourceChangedListener(resourceRefreshListener);
+ AdtPlugin.getDefault().removeTargetListener(targetListener);
if (mClipboard != null) {
mClipboard.dispose();
mClipboard = null;
@@ -580,7 +590,11 @@ public final class UiTreeBlock extends MasterDetailsBlock implements ICommitXml
ui_node = ui_node.getUiParent()) {
segments.add(0, ui_node);
}
- mTreeViewer.setSelection(new TreeSelection(new TreePath(segments.toArray())));
+ if (segments.size() > 0) {
+ mTreeViewer.setSelection(new TreeSelection(new TreePath(segments.toArray())));
+ } else {
+ mTreeViewer.setSelection(null);
+ }
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/NewXmlFileCreationPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/NewXmlFileCreationPage.java
index 4d17176..5781938 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/NewXmlFileCreationPage.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/NewXmlFileCreationPage.java
@@ -23,6 +23,7 @@ import com.android.ide.eclipse.common.AndroidConstants;
import com.android.ide.eclipse.common.project.ProjectChooserHelper;
import com.android.ide.eclipse.editors.descriptors.DocumentDescriptor;
import com.android.ide.eclipse.editors.descriptors.ElementDescriptor;
+import com.android.ide.eclipse.editors.descriptors.IDescriptorProvider;
import com.android.ide.eclipse.editors.menu.descriptors.MenuDescriptors;
import com.android.ide.eclipse.editors.resources.configurations.FolderConfiguration;
import com.android.ide.eclipse.editors.resources.configurations.ResourceQualifier;
@@ -81,6 +82,7 @@ class NewXmlFileCreationPage extends WizardPage {
private final String mXmlns;
private final String mDefaultAttrs;
private final String mDefaultRoot;
+ private final int mTargetApiLevel;
public TypeInfo(String uiName,
String tooltip,
@@ -88,7 +90,8 @@ class NewXmlFileCreationPage extends WizardPage {
Object rootSeed,
String defaultRoot,
String xmlns,
- String defaultAttrs) {
+ String defaultAttrs,
+ int targetApiLevel) {
mUiName = uiName;
mResFolderType = resFolderType;
mTooltip = tooltip;
@@ -96,6 +99,7 @@ class NewXmlFileCreationPage extends WizardPage {
mDefaultRoot = defaultRoot;
mXmlns = xmlns;
mDefaultAttrs = defaultAttrs;
+ mTargetApiLevel = targetApiLevel;
}
/** Returns the UI name for the resource type. Unique. Never null. */
@@ -176,6 +180,13 @@ class NewXmlFileCreationPage extends WizardPage {
String getDefaultAttrs() {
return mDefaultAttrs;
}
+
+ /**
+ * The minimum API level required by the current SDK target to support this feature.
+ */
+ public int getTargetApiLevel() {
+ return mTargetApiLevel;
+ }
}
/**
@@ -190,7 +201,8 @@ class NewXmlFileCreationPage extends WizardPage {
"LinearLayout", // default root
SdkConstants.NS_RESOURCES, // xmlns
"android:layout_width=\"wrap_content\"\n" + // default attributes
- "android:layout_height=\"wrap_content\""
+ "android:layout_height=\"wrap_content\"",
+ 1 // target API level
),
new TypeInfo("Values", // UI name
"An XML file with simple values: colors, strings, dimensions, etc.", // tooltip
@@ -198,7 +210,8 @@ class NewXmlFileCreationPage extends WizardPage {
ResourcesDescriptors.ROOT_ELEMENT, // root seed
null, // default root
null, // xmlns
- null // default attributes
+ null, // default attributes
+ 1 // target API level
),
new TypeInfo("Menu", // UI name
"An XML file that describes an menu.", // tooltip
@@ -206,7 +219,17 @@ class NewXmlFileCreationPage extends WizardPage {
MenuDescriptors.MENU_ROOT_ELEMENT, // root seed
null, // default root
SdkConstants.NS_RESOURCES, // xmlns
- null // default attributes
+ null, // default attributes
+ 1 // target API level
+ ),
+ new TypeInfo("Gadget Provider", // UI name
+ "An XML file that describes a gadget provider.", // tooltip
+ ResourceFolderType.XML, // folder type
+ AndroidTargetData.DESCRIPTOR_GADGET_PROVIDER, // root seed
+ null, // default root
+ SdkConstants.NS_RESOURCES, // xmlns
+ null, // default attributes
+ 3 // target API level
),
new TypeInfo("Preference", // UI name
"An XML file that describes preferences.", // tooltip
@@ -214,15 +237,17 @@ class NewXmlFileCreationPage extends WizardPage {
AndroidTargetData.DESCRIPTOR_PREFERENCES, // root seed
AndroidConstants.CLASS_PREFERENCE_SCREEN, // default root
SdkConstants.NS_RESOURCES, // xmlns
- null // default attributes
+ null, // default attributes
+ 1 // target API level
),
new TypeInfo("Searchable", // UI name
- "An XML file that describes a searchable [TODO].", // tooltip
+ "An XML file that describes a searchable.", // tooltip
ResourceFolderType.XML, // folder type
AndroidTargetData.DESCRIPTOR_SEARCHABLE, // root seed
null, // default root
SdkConstants.NS_RESOURCES, // xmlns
- null // default attributes
+ null, // default attributes
+ 1 // target API level
),
new TypeInfo("Animation", // UI name
"An XML file that describes an animation.", // tooltip
@@ -237,10 +262,14 @@ class NewXmlFileCreationPage extends WizardPage {
},
"set", //$NON-NLS-1$ // default root
null, // xmlns
- null // default attributes
+ null, // default attributes
+ 1 // target API level
),
};
+ /** Number of columns in the grid layout */
+ final static int NUM_COL = 4;
+
/** Absolute destination folder root, e.g. "/res/" */
private static String sResFolderAbs = AndroidConstants.WS_RESOURCES + AndroidConstants.WS_SEP;
/** Relative destination folder root, e.g. "res/" */
@@ -290,7 +319,7 @@ class NewXmlFileCreationPage extends WizardPage {
initializeDialogUnits(parent);
- composite.setLayout(new GridLayout(3, false /*makeColumnsEqualWidth*/));
+ composite.setLayout(new GridLayout(NUM_COL, false /*makeColumnsEqualWidth*/));
composite.setLayoutData(new GridData(GridData.FILL_BOTH));
createProjectGroup(composite);
@@ -303,8 +332,9 @@ class NewXmlFileCreationPage extends WizardPage {
setControl(composite);
// Update state the first time
- initializeRootValues();
initializeFromSelection(mInitialSelection);
+ initializeRootValues();
+ enableTypesBasedOnApi();
validatePage();
}
@@ -419,16 +449,34 @@ class NewXmlFileCreationPage extends WizardPage {
}
/**
+ * Pads the parent with empty cells to match the number of columns of the parent grid.
+ *
+ * @param parent A grid layout with NUM_COL columns
+ * @param col The current number of columns used.
+ * @return 0, the new number of columns used, for convenience.
+ */
+ private int padWithEmptyCells(Composite parent, int col) {
+ for (; col < NUM_COL; ++col) {
+ emptyCell(parent);
+ }
+ col = 0;
+ return col;
+ }
+
+ /**
* Creates the project & filename fields.
* <p/>
- * The parent must be a GridLayout with 3 colums.
+ * The parent must be a GridLayout with NUM_COL colums.
*/
private void createProjectGroup(Composite parent) {
+ int col = 0;
+
// project name
String tooltip = "The Android Project where the new resource file will be created.";
Label label = new Label(parent, SWT.NONE);
label.setText("Project");
label.setToolTipText(tooltip);
+ ++col;
mProjectTextField = new Text(parent, SWT.BORDER);
mProjectTextField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
@@ -438,6 +486,7 @@ class NewXmlFileCreationPage extends WizardPage {
onProjectFieldUpdated();
}
});
+ ++col;
mProjectBrowseButton = new Button(parent, SWT.NONE);
mProjectBrowseButton.setText("Browse...");
@@ -449,12 +498,16 @@ class NewXmlFileCreationPage extends WizardPage {
}
});
mProjectChooserHelper = new ProjectChooserHelper(parent.getShell());
+ ++col;
+ col = padWithEmptyCells(parent, col);
+
// file name
tooltip = "The name of the resource file to create.";
label = new Label(parent, SWT.NONE);
label.setText("File");
label.setToolTipText(tooltip);
+ ++col;
mFileNameTextField = new Text(parent, SWT.BORDER);
mFileNameTextField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
@@ -464,31 +517,32 @@ class NewXmlFileCreationPage extends WizardPage {
validatePage();
}
});
+ ++col;
- emptyCell(parent);
+ padWithEmptyCells(parent, col);
}
/**
* Creates the type field, {@link ConfigurationSelector} and the folder field.
* <p/>
- * The parent must be a GridLayout with 3 colums.
+ * The parent must be a GridLayout with NUM_COL colums.
*/
private void createTypeGroup(Composite parent) {
// separator
Label label = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL);
- label.setLayoutData(newGridData(3, GridData.GRAB_HORIZONTAL));
+ label.setLayoutData(newGridData(NUM_COL, GridData.GRAB_HORIZONTAL));
// label before type radios
label = new Label(parent, SWT.NONE);
label.setText("What type of resource would you like to create?");
- label.setLayoutData(newGridData(3));
+ label.setLayoutData(newGridData(NUM_COL));
// display the types on three columns of radio buttons.
emptyCell(parent);
Composite grid = new Composite(parent, SWT.NONE);
- emptyCell(parent);
+ padWithEmptyCells(parent, 2);
- grid.setLayout(new GridLayout(3, true /*makeColumnsEqualWidth*/));
+ grid.setLayout(new GridLayout(NUM_COL, true /*makeColumnsEqualWidth*/));
SelectionListener radioListener = new SelectionAdapter() {
@Override
@@ -501,23 +555,27 @@ class NewXmlFileCreationPage extends WizardPage {
};
int n = sTypes.length;
- int num_lines = n/3;
- for (int line = 0; line < num_lines; line++) {
- for (int i = 0; i < 3; i++) {
- TypeInfo type = sTypes[line * 3 + i];
- Button radio = new Button(grid, SWT.RADIO);
- type.setWidget(radio);
- radio.setSelection(false);
- radio.setText(type.getUiName());
- radio.setToolTipText(type.getTooltip());
- radio.addSelectionListener(radioListener);
+ int num_lines = (n + NUM_COL/2) / NUM_COL;
+ for (int line = 0, k = 0; line < num_lines; line++) {
+ for (int i = 0; i < NUM_COL; i++, k++) {
+ if (k < n) {
+ TypeInfo type = sTypes[k];
+ Button radio = new Button(grid, SWT.RADIO);
+ type.setWidget(radio);
+ radio.setSelection(false);
+ radio.setText(type.getUiName());
+ radio.setToolTipText(type.getTooltip());
+ radio.addSelectionListener(radioListener);
+ } else {
+ emptyCell(grid);
+ }
}
}
// label before configuration selector
label = new Label(parent, SWT.NONE);
label.setText("What type of resource configuration would you like?");
- label.setLayoutData(newGridData(3));
+ label.setLayoutData(newGridData(NUM_COL));
// configuration selector
emptyCell(parent);
@@ -527,6 +585,7 @@ class NewXmlFileCreationPage extends WizardPage {
gd.heightHint = ConfigurationSelector.HEIGHT_HINT;
mConfigSelector.setLayoutData(gd);
mConfigSelector.setOnChangeListener(new onConfigSelectorUpdated());
+ emptyCell(parent);
// folder name
String tooltip = "The folder where the file will be generated, relative to the project.";
@@ -542,25 +601,23 @@ class NewXmlFileCreationPage extends WizardPage {
onWsFolderPathUpdated();
}
});
-
- emptyCell(parent);
}
/**
* Creates the root element combo.
* <p/>
- * The parent must be a GridLayout with 3 colums.
+ * The parent must be a GridLayout with NUM_COL colums.
*/
private void createRootGroup(Composite parent) {
// separator
Label label = new Label(parent, SWT.SEPARATOR | SWT.HORIZONTAL);
- label.setLayoutData(newGridData(3, GridData.GRAB_HORIZONTAL));
+ label.setLayoutData(newGridData(NUM_COL, GridData.GRAB_HORIZONTAL));
// label before the root combo
String tooltip = "The root element to create in the XML file.";
label = new Label(parent, SWT.NONE);
label.setText("Select the root element for the XML file:");
- label.setLayoutData(newGridData(3));
+ label.setLayoutData(newGridData(NUM_COL));
label.setToolTipText(tooltip);
// root combo
@@ -572,7 +629,7 @@ class NewXmlFileCreationPage extends WizardPage {
mRootElementCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
mRootElementCombo.setToolTipText(tooltip);
- emptyCell(parent);
+ padWithEmptyCells(parent, 2);
}
/**
@@ -690,11 +747,13 @@ class NewXmlFileCreationPage extends WizardPage {
// get the AndroidTargetData from the project
IAndroidTarget target = Sdk.getCurrent().getTarget(mProject);
AndroidTargetData data = Sdk.getCurrent().getTargetData(target);
- ElementDescriptor descriptor = data.getDescriptorProvider(
- (Integer)rootSeed).getDescriptor();
- HashSet<ElementDescriptor> visited = new HashSet<ElementDescriptor>();
- initRootElementDescriptor(roots, descriptor, visited);
+ IDescriptorProvider provider = data.getDescriptorProvider((Integer)rootSeed);
+ ElementDescriptor descriptor = provider.getDescriptor();
+ if (descriptor != null) {
+ HashSet<ElementDescriptor> visited = new HashSet<ElementDescriptor>();
+ initRootElementDescriptor(roots, descriptor, visited);
+ }
// Sort alphabetically.
Collections.sort(roots);
@@ -743,15 +802,7 @@ class NewXmlFileCreationPage extends WizardPage {
}
if (found != mProject) {
- mProject = found;
-
- // update the Type with the new descriptors.
- initializeRootValues();
-
- // update the combo
- updateRootCombo(getSelectedType());
-
- validatePage();
+ changeProject(found);
}
}
@@ -761,17 +812,27 @@ class NewXmlFileCreationPage extends WizardPage {
private void onProjectBrowse() {
IJavaProject p = mProjectChooserHelper.chooseJavaProject(mProjectTextField.getText());
if (p != null) {
- mProject = p.getProject();
+ changeProject(p.getProject());
mProjectTextField.setText(mProject.getName());
-
- // update the Type with the new descriptors.
- initializeRootValues();
-
- // update the combo
- updateRootCombo(getSelectedType());
-
- validatePage();
}
+ }
+
+ /**
+ * Changes mProject to the given new project and update the UI accordingly.
+ */
+ private void changeProject(IProject newProject) {
+ mProject = newProject;
+
+ // enable types based on new API level
+ enableTypesBasedOnApi();
+
+ // update the Type with the new descriptors.
+ initializeRootValues();
+
+ // update the combo
+ updateRootCombo(getSelectedType());
+
+ validatePage();
}
/**
@@ -986,6 +1047,26 @@ class NewXmlFileCreationPage extends WizardPage {
}
/**
+ * Helper method to enable the type radio buttons depending on the current API level.
+ * <p/>
+ * A type radio button is enabled either if:
+ * - if mProject is null, API level 1 is considered valid
+ * - if mProject is !null, the project->target->API must be >= to the type's API level.
+ */
+ private void enableTypesBasedOnApi() {
+
+ IAndroidTarget target = mProject != null ? Sdk.getCurrent().getTarget(mProject) : null;
+ int currentApiLevel = 1;
+ if (target != null) {
+ currentApiLevel = target.getApiVersionNumber();
+ }
+
+ for (TypeInfo type : sTypes) {
+ type.getWidget().setEnabled(type.getTargetApiLevel() <= currentApiLevel);
+ }
+ }
+
+ /**
* Validates the fields, displays errors and warnings.
* Enables the finish button if there are no errors.
*/
@@ -1017,6 +1098,22 @@ class NewXmlFileCreationPage extends WizardPage {
}
}
+ // -- validate type API level
+ if (error == null) {
+ IAndroidTarget target = Sdk.getCurrent().getTarget(mProject);
+ int currentApiLevel = 1;
+ if (target != null) {
+ currentApiLevel = target.getApiVersionNumber();
+ }
+
+ TypeInfo type = getSelectedType();
+
+ if (type.getTargetApiLevel() > currentApiLevel) {
+ error = "The API level of the selected type (e.g. gadget, etc.) is not " +
+ "compatible with the API level of the project.";
+ }
+ }
+
// -- validate folder configuration
if (error == null) {
ConfigurationState state = mConfigSelector.getState();
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/xml/descriptors/XmlDescriptors.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/xml/descriptors/XmlDescriptors.java
index fa1370f..7929b5a 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/xml/descriptors/XmlDescriptors.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/xml/descriptors/XmlDescriptors.java
@@ -53,6 +53,9 @@ public final class XmlDescriptors implements IDescriptorProvider {
/** The root document descriptor for preferences. */
private DocumentDescriptor mPrefDescriptor = new DocumentDescriptor("xml_doc", null /* children */); //$NON-NLS-1$
+ /** The root document descriptor for gadget provider. */
+ private DocumentDescriptor mGadgetDescriptor = new DocumentDescriptor("xml_doc", null /* children */); //$NON-NLS-1$
+
/** @return the root descriptor for both searchable and preferences. */
public DocumentDescriptor getDescriptor() {
return mDescriptor;
@@ -72,6 +75,11 @@ public final class XmlDescriptors implements IDescriptorProvider {
return mPrefDescriptor;
}
+ /** @return the root descriptor for gadget providers. */
+ public DocumentDescriptor getGadgetDescriptor() {
+ return mGadgetDescriptor;
+ }
+
public IDescriptorProvider getSearchableProvider() {
return new IDescriptorProvider() {
public ElementDescriptor getDescriptor() {
@@ -96,6 +104,18 @@ public final class XmlDescriptors implements IDescriptorProvider {
};
}
+ public IDescriptorProvider getGadgetProvider() {
+ return new IDescriptorProvider() {
+ public ElementDescriptor getDescriptor() {
+ return mGadgetDescriptor;
+ }
+
+ public ElementDescriptor[] getRootElementDescriptors() {
+ return mGadgetDescriptor.getChildren();
+ }
+ };
+ }
+
/**
* Updates the document descriptor.
* <p/>
@@ -103,11 +123,13 @@ public final class XmlDescriptors implements IDescriptorProvider {
* all at once.
*
* @param searchableStyleMap The map style=>attributes for <searchable> from the attrs.xml file
+ * @param gadgetStyleMap The map style=>attributes for <gadget-provider> from the attrs.xml file
* @param prefs The list of non-group preference descriptions
* @param prefGroups The list of preference group descriptions
*/
public synchronized void updateDescriptors(
Map<String, DeclareStyleableInfo> searchableStyleMap,
+ Map<String, DeclareStyleableInfo> gadgetStyleMap,
ViewClassInfo[] prefs, ViewClassInfo[] prefGroups) {
XmlnsAttributeDescriptor xmlns = new XmlnsAttributeDescriptor(
@@ -115,12 +137,17 @@ public final class XmlDescriptors implements IDescriptorProvider {
SdkConstants.NS_RESOURCES);
ElementDescriptor searchable = createSearchable(searchableStyleMap, xmlns);
+ ElementDescriptor gadget = createGadgetProviderInfo(gadgetStyleMap, xmlns);
ElementDescriptor preferences = createPreference(prefs, prefGroups, xmlns);
ArrayList<ElementDescriptor> list = new ArrayList<ElementDescriptor>();
if (searchable != null) {
list.add(searchable);
mSearchDescriptor.setChildren(new ElementDescriptor[]{ searchable });
}
+ if (gadget != null) {
+ list.add(gadget);
+ mGadgetDescriptor.setChildren(new ElementDescriptor[]{ gadget });
+ }
if (preferences != null) {
list.add(preferences);
mPrefDescriptor.setChildren(new ElementDescriptor[]{ preferences });
@@ -161,6 +188,28 @@ public final class XmlDescriptors implements IDescriptorProvider {
false /* mandatory */ );
return searchable;
}
+
+ /**
+ * Returns the new ElementDescriptor for <gadget-provider>
+ */
+ private ElementDescriptor createGadgetProviderInfo(
+ Map<String, DeclareStyleableInfo> gadgetStyleMap,
+ XmlnsAttributeDescriptor xmlns) {
+
+ if (gadgetStyleMap == null) {
+ return null;
+ }
+
+ ElementDescriptor gadget = createElement(gadgetStyleMap,
+ "GadgetProviderInfo", //$NON-NLS-1$ styleName
+ "gadget-provider", //$NON-NLS-1$ xmlName
+ "Gadget Provider", // uiName
+ null, // sdk url
+ xmlns, // extraAttribute
+ null, // childrenElements
+ false /* mandatory */ );
+ return gadget;
+ }
/**
* Returns a new ElementDescriptor constructed from the information given here