aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml18
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/PreCompilerBuilder.java7
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ResourceManagerBuilder.java1
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AndroidLaunchController.java5
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DeviceChooserDialog.java78
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/EmulatorConfigTab.java3
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/ProjectHelper.java10
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetData.java6
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/AndroidTargetParser.java16
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectCreationPage.java62
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestHelper.java241
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java254
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/XmlErrorHandler.java28
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/AndroidContentAssist.java12
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/ProjectCallback.java19
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/descriptors/LayoutDescriptors.java22
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/model/UiClassAttributeNode.java6
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/CompiledResourcesMonitor.java39
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/NewXmlFileCreationPage.java8
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/xml/descriptors/XmlDescriptors.java46
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/.classpath2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/common/project/AndroidManifestHelperTest.java97
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/common/project/AndroidManifestParserTest.java94
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/mock/FileMock.java58
-rw-r--r--emulator/keymaps/AVRCP.kl7
-rw-r--r--emulator/keymaps/Android.mk5
-rw-r--r--hierarchyviewer/src/com/android/hierarchyviewer/scene/ProfilesLoader.java77
-rw-r--r--hierarchyviewer/src/com/android/hierarchyviewer/ui/Workspace.java52
-rw-r--r--hierarchyviewer/src/com/android/hierarchyviewer/ui/model/ProfilesTableModel.java68
-rw-r--r--sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java5
-rw-r--r--sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/ApkConfigWidget.java2
-rw-r--r--sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/AvdSelector.java73
32 files changed, 852 insertions, 569 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml b/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml
index 4dfcc07..f86f5b2 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml
@@ -474,15 +474,6 @@
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"
@@ -491,6 +482,15 @@
toolbarPath="android_project"
tooltip="Opens a wizard to help create a new Android XML file">
</action>
+ <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>
</actionSet>
</extension>
<extension
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 fb1608c..c508283 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
@@ -21,7 +21,6 @@ import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.project.FixLaunchConfig;
import com.android.ide.eclipse.adt.sdk.Sdk;
import com.android.ide.eclipse.common.AndroidConstants;
-import com.android.ide.eclipse.common.project.AndroidManifestHelper;
import com.android.ide.eclipse.common.project.AndroidManifestParser;
import com.android.ide.eclipse.common.project.BaseProjectHelper;
import com.android.ide.eclipse.common.project.XmlErrorHandler.BasicXmlErrorListener;
@@ -272,7 +271,7 @@ public class PreCompilerBuilder extends BaseBuilder {
// get the manifest file
- IFile manifest = AndroidManifestHelper.getManifest(project);
+ IFile manifest = AndroidManifestParser.getManifest(project);
if (manifest == null) {
String msg = String.format(Messages.s_File_Missing,
@@ -743,7 +742,7 @@ public class PreCompilerBuilder extends BaseBuilder {
// create it if needed
if (destinationFolder.exists() == false && createFolders) {
destinationFolder.create(true /*force*/, true /*local*/,
- new SubProgressMonitor(monitor, 10));;
+ new SubProgressMonitor(monitor, 10));
}
// Build the Java file name from the aidl name.
@@ -824,7 +823,7 @@ public class PreCompilerBuilder extends BaseBuilder {
/**
* Scans a folder and fills the list of aidl files to compile.
* @param sourceFolder the root source folder.
- * @param container The folder to scan.
+ * @param folder The folder to scan.
*/
private void scanFolderForAidl(IFolder sourceFolder, IFolder folder) {
try {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ResourceManagerBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ResourceManagerBuilder.java
index 0255f9f..035aa5b 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ResourceManagerBuilder.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ResourceManagerBuilder.java
@@ -176,6 +176,7 @@ public class ResourceManagerBuilder extends BaseBuilder {
"Creating 'gen' source folder for generated Java files");
genFolder.create(true /* force */, true /* local */,
new SubProgressMonitor(monitor, 10));
+ genFolder.setDerived(true);
}
// add it to the source folder list, if needed only (or it will throw)
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AndroidLaunchController.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AndroidLaunchController.java
index 9c5f09b..111d6b3 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AndroidLaunchController.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AndroidLaunchController.java
@@ -31,7 +31,7 @@ import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.launch.DeviceChooserDialog.DeviceChooserResponse;
import com.android.ide.eclipse.adt.project.ProjectHelper;
import com.android.ide.eclipse.adt.sdk.Sdk;
-import com.android.ide.eclipse.common.project.AndroidManifestHelper;
+import com.android.ide.eclipse.common.project.AndroidManifestParser;
import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.SdkManager;
import com.android.sdklib.avd.AvdManager;
@@ -584,8 +584,7 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
ArrayList<IResource> array = new ArrayList<IResource>(2);
array.add(project);
- AndroidManifestHelper helper = new AndroidManifestHelper(project);
- IFile manifest = helper.getManifestIFile();
+ IFile manifest = AndroidManifestParser.getManifest(project);
if (manifest != null) {
array.add(manifest);
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DeviceChooserDialog.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DeviceChooserDialog.java
index 275addf..a960bda 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DeviceChooserDialog.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/DeviceChooserDialog.java
@@ -36,12 +36,8 @@ import com.android.sdkuilib.AvdSelector;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.preference.IPreferenceStore;
-import org.eclipse.jface.viewers.DoubleClickEvent;
-import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ILabelProviderListener;
-import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredContentProvider;
-import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
@@ -62,6 +58,12 @@ import org.eclipse.swt.widgets.Table;
import java.util.ArrayList;
+/**
+ * A dialog that lets the user choose a device to deploy an application.
+ * The user can either choose an exiting running device (including running emulators)
+ * or start a new emulator using an Android Virtual Device configuration that matches
+ * the current project.
+ */
public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener {
private final static int ICON_WIDTH = 16;
@@ -373,15 +375,27 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener
mViewer.setContentProvider(new ContentProvider());
mViewer.setLabelProvider(new LabelProvider());
mViewer.setInput(AndroidDebugBridge.getBridge());
- mViewer.addDoubleClickListener(new IDoubleClickListener() {
- public void doubleClick(DoubleClickEvent event) {
- ISelection selection = event.getSelection();
- if (selection instanceof IStructuredSelection) {
- IStructuredSelection structuredSelection = (IStructuredSelection)selection;
- Object object = structuredSelection.getFirstElement();
- if (object instanceof Device) {
- mResponse.setDeviceToUse((Device)object);
- }
+
+ mDeviceTable.addSelectionListener(new SelectionAdapter() {
+ /**
+ * Handles single-click selection on the device selector.
+ * {@inheritDoc}
+ */
+ @Override
+ public void widgetSelected(SelectionEvent e) {
+ handleDeviceSelection();
+ }
+
+ /**
+ * Handles double-click selection on the device selector.
+ * Note that the single-click handler will probably already have been called.
+ * {@inheritDoc}
+ */
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ handleDeviceSelection();
+ if (isOkButtonEnabled()) {
+ okPressed();
}
}
});
@@ -397,18 +411,14 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener
layout.marginLeft = 30;
offsetComp.setLayout(layout);
- mPreferredAvdSelector = new AvdSelector(offsetComp, getNonRunningAvds(), mProjectTarget,
- false /*allowMultipleSelection*/);
+ mPreferredAvdSelector = new AvdSelector(offsetComp, getNonRunningAvds(), mProjectTarget);
mPreferredAvdSelector.setTableHeightHint(100);
mPreferredAvdSelector.setEnabled(false);
- mDeviceTable.addSelectionListener(new SelectionAdapter() {
- @Override
- public void widgetSelected(SelectionEvent e) {
- handleDeviceSelection();
- }
- });
-
mPreferredAvdSelector.setSelectionListener(new SelectionAdapter() {
+ /**
+ * Handles single-click selection on the AVD selector.
+ * {@inheritDoc}
+ */
@Override
public void widgetSelected(SelectionEvent e) {
if (mDisableAvdSelectionChange == false) {
@@ -416,6 +426,22 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener
enableOkButton();
}
}
+
+ /**
+ * Handles double-click selection on the AVD selector.
+ *
+ * Note that the single-click handler will probably already have been called
+ * but the selected item can have changed in between.
+ *
+ * {@inheritDoc}
+ */
+ @Override
+ public void widgetDefaultSelected(SelectionEvent e) {
+ widgetSelected(e);
+ if (isOkButtonEnabled()) {
+ okPressed();
+ }
+ }
});
AndroidDebugBridge.addDeviceChangeListener(this);
@@ -586,6 +612,14 @@ public class DeviceChooserDialog extends Dialog implements IDeviceChangeListener
okButton.setEnabled(mResponse.getAvdToLaunch() != null);
}
}
+
+ /**
+ * Returns true if the ok button is enabled.
+ */
+ private boolean isOkButtonEnabled() {
+ Button okButton = getButton(IDialogConstants.OK_ID);
+ return okButton.isEnabled();
+ }
/**
* Executes the {@link Runnable} in the UI thread.
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/EmulatorConfigTab.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/EmulatorConfigTab.java
index 5b4cdbb..b898f63 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/EmulatorConfigTab.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/EmulatorConfigTab.java
@@ -178,8 +178,7 @@ public class EmulatorConfigTab extends AbstractLaunchConfigurationTab {
mPreferredAvdLabel = new Label(offsetComp, SWT.NONE);
mPreferredAvdLabel.setText("Select a preferred Android Virtual Device:");
AvdInfo[] avds = new AvdInfo[0];
- mPreferredAvdSelector = new AvdSelector(offsetComp, avds,
- false /*allowMultipleSelection*/);
+ mPreferredAvdSelector = new AvdSelector(offsetComp, avds);
mPreferredAvdSelector.setTableHeightHint(100);
mPreferredAvdSelector.setSelectionListener(new SelectionAdapter() {
@Override
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/ProjectHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/ProjectHelper.java
index b1f8ffc..fd0c045 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/ProjectHelper.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/ProjectHelper.java
@@ -19,9 +19,9 @@ package com.android.ide.eclipse.adt.project;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.adt.project.internal.AndroidClasspathContainerInitializer;
import com.android.ide.eclipse.common.AndroidConstants;
-import com.android.ide.eclipse.common.project.AndroidManifestHelper;
import com.android.ide.eclipse.common.project.AndroidManifestParser;
+import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IProjectDescription;
@@ -389,18 +389,16 @@ public final class ProjectHelper {
continue;
}
- AndroidManifestHelper androidManifest = new AndroidManifestHelper(p);
-
// check that there is indeed a manifest file.
- if (androidManifest.getManifestIFile() == null) {
+ IFile manifestFile = AndroidManifestParser.getManifest(p);
+ if (manifestFile == null) {
// no file? skip this project.
continue;
}
AndroidManifestParser parser = null;
try {
- parser = AndroidManifestParser.parseForData(
- androidManifest.getManifestIFile());
+ parser = AndroidManifestParser.parseForData(manifestFile);
} catch (CoreException e) {
// skip this project.
continue;
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 a8852e7..34391c2 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
@@ -44,7 +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 int DESCRIPTOR_APPWIDGET_PROVIDER = 8;
public final static class LayoutBridge {
/** Link to the layout bridge */
@@ -158,8 +158,8 @@ public class AndroidTargetData {
return ResourcesDescriptors.getInstance();
case DESCRIPTOR_PREFERENCES:
return mXmlDescriptors.getPreferencesProvider();
- case DESCRIPTOR_GADGET_PROVIDER:
- return mXmlDescriptors.getGadgetProvider();
+ case DESCRIPTOR_APPWIDGET_PROVIDER:
+ return mXmlDescriptors.getAppWidgetProvider();
case DESCRIPTOR_SEARCHABLE:
return mXmlDescriptors.getSearchableProvider();
default :
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 04baeba..67eec78 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
@@ -203,9 +203,9 @@ public final class AndroidTargetParser {
attrsManifestXmlParser);
Map<String, Map<String, Integer>> enumValueMap = attrsXmlParser.getEnumFlagValues();
- Map<String, DeclareStyleableInfo> xmlGadgetMap = null;
+ Map<String, DeclareStyleableInfo> xmlAppWidgetMap = null;
if (mAndroidTarget.getApiVersionNumber() >= 3) {
- xmlGadgetMap = collectGadgetDefinitions(attrsXmlParser);
+ xmlAppWidgetMap = collectAppWidgetDefinitions(attrsXmlParser);
}
if (progress.isCanceled()) {
@@ -241,7 +241,7 @@ public final class AndroidTargetParser {
XmlDescriptors xmlDescriptors = new XmlDescriptors();
xmlDescriptors.updateDescriptors(
xmlSearchableMap,
- xmlGadgetMap,
+ xmlAppWidgetMap,
preferencesInfo,
preferenceGroupsInfo);
progress.worked(1);
@@ -611,23 +611,23 @@ public final class AndroidTargetParser {
}
/**
- * Collects all gadgetProviderInfo definition information from the attrs.xml and returns it.
+ * Collects all appWidgetProviderInfo definition information from the attrs.xml and returns it.
*
* @param attrsXmlParser The parser of the attrs.xml file
*/
- private Map<String, DeclareStyleableInfo> collectGadgetDefinitions(
+ private Map<String, DeclareStyleableInfo> collectAppWidgetDefinitions(
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$
+ for (String key : new String[] { "AppWidgetProviderInfo" }) { //$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$
+ "AppWidget 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$
+ String.format("AppWidget declare-styleable %1$s not found in file %2$s", //$NON-NLS-1$
key, attrsXmlParser.getOsAttrsXmlPath()));
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectCreationPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectCreationPage.java
index 33ec2bc..6c4f4ba 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectCreationPage.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectCreationPage.java
@@ -24,7 +24,7 @@ package com.android.ide.eclipse.adt.wizards.newproject;
import com.android.ide.eclipse.adt.sdk.Sdk;
import com.android.ide.eclipse.common.AndroidConstants;
-import com.android.ide.eclipse.common.project.AndroidManifestHelper;
+import com.android.ide.eclipse.common.project.AndroidManifestParser;
import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.SdkConstants;
import com.android.sdklib.project.ProjectProperties;
@@ -36,6 +36,7 @@ import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Path;
@@ -821,26 +822,41 @@ public class NewProjectCreationPage extends WizardPage {
Path path = new Path(f.getPath());
String osPath = path.append(AndroidConstants.FN_ANDROID_MANIFEST).toOSString();
- AndroidManifestHelper manifest = new AndroidManifestHelper(osPath);
- if (!manifest.exists()) {
+
+ AndroidManifestParser manifestData = null;
+ try {
+ manifestData = AndroidManifestParser.parseForData(osPath);
+ } catch (CoreException e1) {
+ // ignore any parsing issue
+ }
+ if (manifestData == null) {
return;
}
String packageName = null;
String activityName = null;
- String minSdkVersion = null;
+ int minSdkVersion = 0; // 0 means no minSdkVersion provided in the manifest
try {
- packageName = manifest.getPackageName();
- activityName = manifest.getActivityName(1);
- minSdkVersion = manifest.getMinSdkVersion();
+ packageName = manifestData.getPackage();
+ minSdkVersion = manifestData.getApiLevelRequirement();
+
+ // try to get the first launcher activity. If none, just take the first activity.
+ activityName = manifestData.getLauncherActivity();
+ if (activityName == null) {
+ String[] activities = manifestData.getActivities();
+ if (activities != null && activities.length > 0) {
+ activityName = activities[0];
+ }
+ }
} catch (Exception e) {
// ignore exceptions
}
-
if (packageName != null && packageName.length() > 0) {
mPackageNameField.setText(packageName);
}
+
+ activityName = AndroidManifestParser.extractActivityName(activityName, packageName);
if (activityName != null && activityName.length() > 0) {
mInternalActivityNameUpdate = true;
@@ -917,12 +933,10 @@ public class NewProjectCreationPage extends WizardPage {
}
}
- if (!foundTarget && minSdkVersion != null) {
+ if (!foundTarget && minSdkVersion > 0) {
try {
- int sdkVersion = Integer.parseInt(minSdkVersion);
-
for (IAndroidTarget target : mSdkTargetSelector.getTargets()) {
- if (target.getApiVersionNumber() == sdkVersion) {
+ if (target.getApiVersionNumber() == minSdkVersion) {
mSdkTargetSelector.setSelection(target);
foundTarget = true;
break;
@@ -945,7 +959,8 @@ public class NewProjectCreationPage extends WizardPage {
if (!foundTarget) {
mInternalMinSdkVersionUpdate = true;
- mMinSdkVersionField.setText(minSdkVersion == null ? "" : minSdkVersion); //$NON-NLS-1$
+ mMinSdkVersionField.setText(
+ minSdkVersion <= 0 ? "" : Integer.toString(minSdkVersion)); //$NON-NLS-1$
mInternalMinSdkVersionUpdate = false;
}
}
@@ -1072,8 +1087,8 @@ public class NewProjectCreationPage extends WizardPage {
// Check there's an android manifest in the directory
String osPath = path.append(AndroidConstants.FN_ANDROID_MANIFEST).toOSString();
- AndroidManifestHelper manifest = new AndroidManifestHelper(osPath);
- if (!manifest.exists()) {
+ File manifestFile = new File(osPath);
+ if (!manifestFile.isFile()) {
return setStatus(
String.format("File %1$s not found in %2$s.",
AndroidConstants.FN_ANDROID_MANIFEST, f.getName()),
@@ -1081,15 +1096,24 @@ public class NewProjectCreationPage extends WizardPage {
}
// Parse it and check the important fields.
- String packageName = manifest.getPackageName();
+ AndroidManifestParser manifestData;
+ try {
+ manifestData = AndroidManifestParser.parseForData(osPath);
+ } catch (CoreException e) {
+ return setStatus(
+ String.format("File %1$s could not be parsed.", osPath),
+ MSG_ERROR);
+ }
+
+ String packageName = manifestData.getPackage();
if (packageName == null || packageName.length() == 0) {
return setStatus(
String.format("No package name defined in %1$s.", osPath),
MSG_ERROR);
}
- String activityName = manifest.getActivityName(1);
- if (activityName == null || activityName.length() == 0) {
+ String[] activities = manifestData.getActivities();
+ if (activities == null || activities.length == 0) {
// This is acceptable now as long as no activity needs to be created
if (isCreateActivity()) {
return setStatus(
@@ -1097,7 +1121,7 @@ public class NewProjectCreationPage extends WizardPage {
MSG_ERROR);
}
}
-
+
// If there's already a .project, tell the user to use import instead.
if (path.append(".project").toFile().exists()) { //$NON-NLS-1$
return setStatus("An Eclipse project already exists in this directory. Consider using File > Import > Existing Project instead.",
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestHelper.java
deleted file mode 100644
index cd238d2..0000000
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestHelper.java
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Copyright (C) 2007 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.common.project;
-
-import com.android.ide.eclipse.common.AndroidConstants;
-
-import org.eclipse.core.resources.IFile;
-import org.eclipse.core.resources.IProject;
-import org.eclipse.core.resources.IResource;
-import org.eclipse.core.runtime.CoreException;
-import org.xml.sax.InputSource;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-
-import javax.xml.xpath.XPath;
-import javax.xml.xpath.XPathExpressionException;
-
-/**
- * Utility class that manages the AndroidManifest.xml file.
- * <p/>
- * All the get method work by XPath. Repeated calls to those may warrant using
- * {@link AndroidManifestParser} instead.
- */
-public class AndroidManifestHelper {
- private IFile mManifestIFile;
- private File mManifestFile;
- private XPath mXPath;
-
- /**
- * Creates an AndroidManifest based on an existing Eclipse {@link IProject} object.
- * </p>
- * Use {@link #exists()} to check if the manifest file really exists in the project.
- *
- * @param project The project to search for the manifest.
- */
- public AndroidManifestHelper(IProject project) {
- mXPath = AndroidXPathFactory.newXPath();
- mManifestIFile = getManifest(project);
- }
-
- /**
- * Creates an AndroidManifest based on a file path.
- * <p/>
- * Use {@link #exists()} to check if the manifest file really exists.
- *
- * @param osManifestFilePath the os path to the AndroidManifest.xml file.
- */
- public AndroidManifestHelper(String osManifestFilePath) {
- mXPath = AndroidXPathFactory.newXPath();
- mManifestFile = new File(osManifestFilePath);
- }
-
-
- /**
- * Returns the underlying {@link IFile} for the android manifest XML file, if found in the
- * given Eclipse project.
- *
- * Always return null if the constructor that takes an {@link IProject} was NOT called.
- *
- * @return The IFile for the androidManifest.xml or null if no such file could be found.
- */
- public IFile getManifestIFile() {
- return mManifestIFile;
- }
-
- /**
- * Returns the underlying {@link File} for the android manifest XML file.
- */
- public File getManifestFile() {
- if (mManifestIFile != null) {
- return mManifestIFile.getLocation().toFile();
- }
-
- return mManifestFile;
- }
-
- /**
- * Returns the package name defined in the manifest file.
- *
- * @return A String object with the package or null if any error happened.
- */
- public String getPackageName() {
- try {
- return mXPath.evaluate("/manifest/@package", getSource()); //$NON-NLS-1$
- } catch (XPathExpressionException e1) {
- // If the XPath failed to evaluate, we'll return null.
- } catch (Exception e) {
- // if this happens this is due to the resource being out of sync.
- // so we must refresh it and do it again
-
- // for any other kind of exception we must return null as well;
- }
-
- return null;
- }
-
- /**
- * Returns the minSdkVersion defined in the manifest file.
- *
- * @return A String object with the package or null if any error happened.
- */
- public String getMinSdkVersion() {
- try {
- return mXPath.evaluate("/manifest/uses-sdk/@" //$NON-NLS-1$
- + AndroidXPathFactory.DEFAULT_NS_PREFIX
- + ":minSdkVersion", getSource()); //$NON-NLS-1$
- } catch (XPathExpressionException e1) {
- // If the XPath failed to evaluate, we'll return null.
- } catch (Exception e) {
- // if this happens this is due to the resource being out of sync.
- // so we must refresh it and do it again
-
- // for any other kind of exception we must return null as well;
- }
-
- return null;
- }
- /**
- * Returns the i-th activity defined in the manifest file.
- *
- * @param index The 1-based index of the activity to return.
- * @return A String object with the activity or null if any error happened.
- */
- public String getActivityName(int index) {
- try {
- return mXPath.evaluate("/manifest/application/activity[" //$NON-NLS-1$
- + index
- + "]/@" //$NON-NLS-1$
- + AndroidXPathFactory.DEFAULT_NS_PREFIX +":name", //$NON-NLS-1$
- getSource());
- } catch (XPathExpressionException e1) {
- // If the XPath failed to evaluate, we'll return null.
- } catch (Exception e) {
- // if this happens this is due to the resource being out of sync.
- // so we must refresh it and do it again
-
- // for any other kind of exception we must return null as well;
- }
- return null;
- }
-
- /**
- * Returns an IFile object representing the manifest for the specified
- * project.
- *
- * @param project The project containing the manifest file.
- * @return An IFile object pointing to the manifest or null if the manifest
- * is missing.
- */
- public static IFile getManifest(IProject project) {
- IResource r = project.findMember(AndroidConstants.WS_SEP
- + AndroidConstants.FN_ANDROID_MANIFEST);
-
- if (r == null || r.exists() == false || (r instanceof IFile) == false) {
- return null;
- }
- return (IFile) r;
- }
-
- /**
- * Combines a java package, with a class value from the manifest to make a fully qualified
- * class name
- * @param javaPackage the java package from the manifest.
- * @param className the class name from the manifest.
- * @return the fully qualified class name.
- */
- public static String combinePackageAndClassName(String javaPackage, String className) {
- if (className == null || className.length() == 0) {
- return javaPackage;
- }
- if (javaPackage == null || javaPackage.length() == 0) {
- return className;
- }
-
- // the class name can be a subpackage (starts with a '.'
- // char), a simple class name (no dot), or a full java package
- boolean startWithDot = (className.charAt(0) == '.');
- boolean hasDot = (className.indexOf('.') != -1);
- if (startWithDot || hasDot == false) {
-
- // add the concatenation of the package and class name
- if (startWithDot) {
- return javaPackage + className;
- } else {
- return javaPackage + '.' + className;
- }
- } else {
- // just add the class as it should be a fully qualified java name.
- return className;
- }
- }
-
-
-
- /**
- * Returns true either if an androidManifest.xml file was found in the project
- * or if the given file path exists.
- */
- public boolean exists() {
- if (mManifestIFile != null) {
- return mManifestIFile.exists();
- } else if (mManifestFile != null) {
- return mManifestFile.exists();
- }
-
- return false;
- }
-
- /**
- * Returns an InputSource for XPath.
- *
- * @throws FileNotFoundException if file does not exist.
- * @throws CoreException if the {@link IFile} does not exist.
- */
- private InputSource getSource() throws FileNotFoundException, CoreException {
- if (mManifestIFile != null) {
- return new InputSource(mManifestIFile.getContents());
- } else if (mManifestFile != null) {
- return new InputSource(new FileReader(mManifestFile));
- }
-
- return null;
- }
-
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java
index 850c59d..b2817ff 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java
@@ -22,6 +22,8 @@ import com.android.sdklib.SdkConstants;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.IJavaProject;
import org.xml.sax.Attributes;
@@ -30,6 +32,8 @@ import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
+import java.io.File;
+import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Set;
@@ -56,6 +60,8 @@ public class AndroidManifestParser {
private final static String NODE_ACTION = "action"; //$NON-NLS-1$
private final static String NODE_CATEGORY = "category"; //$NON-NLS-1$
private final static String NODE_USES_SDK = "uses-sdk"; //$NON-NLS-1$
+ private final static String NODE_INSTRUMENTATION = "instrumentation"; //$NON-NLS-1$
+ private final static String NODE_USES_LIBRARY = "uses-library"; //$NON-NLS-1$
private final static int LEVEL_MANIFEST = 0;
private final static int LEVEL_APPLICATION = 1;
@@ -66,6 +72,12 @@ public class AndroidManifestParser {
private final static String ACTION_MAIN = "android.intent.action.MAIN"; //$NON-NLS-1$
private final static String CATEGORY_LAUNCHER = "android.intent.category.LAUNCHER"; //$NON-NLS-1$
+ /**
+ * XML error & data handler used when parsing the AndroidManifest.xml file.
+ * <p/>
+ * This serves both as an {@link XmlErrorHandler} to report errors and as a data repository
+ * to collect data from the manifest.
+ */
private static class ManifestHandler extends XmlErrorHandler {
//--- data read from the parsing
@@ -82,6 +94,10 @@ public class AndroidManifestParser {
private Boolean mDebuggable = null;
/** API level requirement. if 0 the attribute was not present. */
private int mApiLevelRequirement = 0;
+ /** List of all instrumentations declared by the manifest */
+ private final ArrayList<String> mInstrumentations = new ArrayList<String>();
+ /** List of all libraries in use declared by the manifest */
+ private final ArrayList<String> mLibraries = new ArrayList<String>();
//--- temporary data/flags used during parsing
private IJavaProject mJavaProject;
@@ -95,12 +111,13 @@ public class AndroidManifestParser {
private Locator mLocator;
/**
- *
- * @param manifestFile
- * @param errorListener
- * @param gatherData
- * @param javaProject
- * @param markErrors
+ * Creates a new {@link ManifestHandler}, which is also an {@link XmlErrorHandler}.
+ *
+ * @param manifestFile The manifest file being parsed. Can be null.
+ * @param errorListener An optional error listener.
+ * @param gatherData True if data should be gathered.
+ * @param javaProject The java project holding the manifest file. Can be null.
+ * @param markErrors True if errors should be marked as Eclipse Markers on the resource.
*/
ManifestHandler(IFile manifestFile, XmlErrorListener errorListener,
boolean gatherData, IJavaProject javaProject, boolean markErrors) {
@@ -160,6 +177,23 @@ public class AndroidManifestParser {
return mApiLevelRequirement;
}
+ /**
+ * Returns the list of instrumentations found in the manifest.
+ * @return An array of instrumentation names, or empty if no instrumentations were
+ * found.
+ */
+ String[] getInstrumentations() {
+ return mInstrumentations.toArray(new String[mInstrumentations.size()]);
+ }
+
+ /**
+ * Returns the list of libraries in use found in the manifest.
+ * @return An array of library names, or empty if no libraries were found.
+ */
+ String[] getUsesLibraries() {
+ return mLibraries.toArray(new String[mLibraries.size()]);
+ }
+
/* (non-Javadoc)
* @see org.xml.sax.helpers.DefaultHandler#setDocumentLocator(org.xml.sax.Locator)
*/
@@ -217,7 +251,13 @@ public class AndroidManifestParser {
} catch (NumberFormatException e) {
handleError(e, -1 /* lineNumber */);
}
- }
+ } else if (NODE_INSTRUMENTATION.equals(localName)) {
+ value = getAttributeValue(attributes, ATTRIBUTE_NAME,
+ true /* hasNamespace */);
+ if (value != null) {
+ mInstrumentations.add(value);
+ }
+ }
break;
case LEVEL_ACTIVITY:
if (NODE_ACTIVITY.equals(localName)) {
@@ -232,7 +272,13 @@ public class AndroidManifestParser {
} else if (NODE_PROVIDER.equals(localName)) {
processNode(attributes, AndroidConstants.CLASS_CONTENTPROVIDER);
mValidLevel++;
- }
+ } else if (NODE_USES_LIBRARY.equals(localName)) {
+ value = getAttributeValue(attributes, ATTRIBUTE_NAME,
+ true /* hasNamespace */);
+ if (value != null) {
+ mLibraries.add(value);
+ }
+ }
break;
case LEVEL_INTENT_FILTER:
// only process this level if we are in an activity
@@ -355,8 +401,7 @@ public class AndroidManifestParser {
String activityName = getAttributeValue(attributes, ATTRIBUTE_NAME,
true /* hasNamespace */);
if (activityName != null) {
- mCurrentActivity = AndroidManifestHelper.combinePackageAndClassName(mPackage,
- activityName);
+ mCurrentActivity = combinePackageAndClassName(mPackage, activityName);
mActivities.add(mCurrentActivity);
if (mMarkErrors) {
@@ -387,8 +432,7 @@ public class AndroidManifestParser {
String serviceName = getAttributeValue(attributes, ATTRIBUTE_NAME,
true /* hasNamespace */);
if (serviceName != null) {
- serviceName = AndroidManifestHelper.combinePackageAndClassName(mPackage,
- serviceName);
+ serviceName = combinePackageAndClassName(mPackage, serviceName);
if (mMarkErrors) {
checkClass(serviceName, superClassName, false /* testVisibility */);
@@ -412,6 +456,9 @@ public class AndroidManifestParser {
* the class or of its constructors.
*/
private void checkClass(String className, String superClassName, boolean testVisibility) {
+ if (mJavaProject == null) {
+ return;
+ }
// we need to check the validity of the activity.
String result = BaseProjectHelper.testClassForManifest(mJavaProject,
className, superClassName, testVisibility);
@@ -477,6 +524,8 @@ public class AndroidManifestParser {
private final String[] mProcesses;
private final Boolean mDebuggable;
private final int mApiLevelRequirement;
+ private final String[] mInstrumentations;
+ private final String[] mLibraries;
static {
sParserFactory = SAXParserFactory.newInstance();
@@ -484,8 +533,12 @@ public class AndroidManifestParser {
}
/**
- * Parses the Android Manifest, and returns an object containing
- * the result of the parsing.
+ * Parses the Android Manifest, and returns an object containing the result of the parsing.
+ * <p/>
+ * This method is useful to parse a specific {@link IFile} in a Java project.
+ * <p/>
+ * If you only want to gather data, consider {@link #parseForData(IFile)} instead.
+ *
* @param javaProject The java project.
* @param manifestFile the {@link IFile} representing the manifest file.
* @param errorListener
@@ -496,8 +549,12 @@ public class AndroidManifestParser {
* @return an {@link AndroidManifestParser} or null if the parsing failed.
* @throws CoreException
*/
- public static AndroidManifestParser parse(IJavaProject javaProject, IFile manifestFile,
- XmlErrorListener errorListener, boolean gatherData, boolean markErrors)
+ public static AndroidManifestParser parse(
+ IJavaProject javaProject,
+ IFile manifestFile,
+ XmlErrorListener errorListener,
+ boolean gatherData,
+ boolean markErrors)
throws CoreException {
try {
SAXParser parser = sParserFactory.newSAXParser();
@@ -512,7 +569,51 @@ public class AndroidManifestParser {
return new AndroidManifestParser(manifestHandler.getPackage(),
manifestHandler.getActivities(), manifestHandler.getLauncherActivity(),
manifestHandler.getProcesses(), manifestHandler.getDebuggable(),
- manifestHandler.getApiLevelRequirement());
+ manifestHandler.getApiLevelRequirement(), manifestHandler.getInstrumentations(),
+ manifestHandler.getUsesLibraries());
+ } catch (ParserConfigurationException e) {
+ } catch (SAXException e) {
+ } catch (IOException e) {
+ } finally {
+ }
+
+ return null;
+ }
+
+ /**
+ * Parses the Android Manifest, and returns an object containing the result of the parsing.
+ * <p/>
+ * This version parses a real {@link File} file given by an actual path, which is useful for
+ * parsing a file that is not part of an Eclipse Java project.
+ * <p/>
+ * It assumes errors cannot be marked on the file and that data gathering is enabled.
+ *
+ * @param manifestFile the manifest file to parse.
+ * @return an {@link AndroidManifestParser} or null if the parsing failed.
+ * @throws CoreException
+ */
+ private static AndroidManifestParser parse(File manifestFile)
+ throws CoreException {
+ try {
+ SAXParser parser = sParserFactory.newSAXParser();
+
+ ManifestHandler manifestHandler = new ManifestHandler(
+ null, //manifestFile
+ null, //errorListener
+ true, //gatherData
+ null, //javaProject
+ false //markErrors
+ );
+
+ parser.parse(new InputSource(new FileReader(manifestFile)), manifestHandler);
+
+ // get the result from the handler
+
+ return new AndroidManifestParser(manifestHandler.getPackage(),
+ manifestHandler.getActivities(), manifestHandler.getLauncherActivity(),
+ manifestHandler.getProcesses(), manifestHandler.getDebuggable(),
+ manifestHandler.getApiLevelRequirement(), manifestHandler.getInstrumentations(),
+ manifestHandler.getUsesLibraries());
} catch (ParserConfigurationException e) {
} catch (SAXException e) {
} catch (IOException e) {
@@ -535,13 +636,16 @@ public class AndroidManifestParser {
* @return an {@link AndroidManifestParser} or null if the parsing failed.
* @throws CoreException
*/
- public static AndroidManifestParser parse(IJavaProject javaProject,
- XmlErrorListener errorListener, boolean gatherData, boolean markErrors)
+ public static AndroidManifestParser parse(
+ IJavaProject javaProject,
+ XmlErrorListener errorListener,
+ boolean gatherData,
+ boolean markErrors)
throws CoreException {
try {
SAXParser parser = sParserFactory.newSAXParser();
- IFile manifestFile = AndroidManifestHelper.getManifest(javaProject.getProject());
+ IFile manifestFile = getManifest(javaProject.getProject());
if (manifestFile != null) {
ManifestHandler manifestHandler = new ManifestHandler(manifestFile,
errorListener, gatherData, javaProject, markErrors);
@@ -552,7 +656,8 @@ public class AndroidManifestParser {
return new AndroidManifestParser(manifestHandler.getPackage(),
manifestHandler.getActivities(), manifestHandler.getLauncherActivity(),
manifestHandler.getProcesses(), manifestHandler.getDebuggable(),
- manifestHandler.getApiLevelRequirement());
+ manifestHandler.getApiLevelRequirement(),
+ manifestHandler.getInstrumentations(), manifestHandler.getUsesLibraries());
}
} catch (ParserConfigurationException e) {
} catch (SAXException e) {
@@ -589,6 +694,18 @@ public class AndroidManifestParser {
}
/**
+ * Parses the manifest file, and collects data.
+ *
+ * @param osManifestFilePath The OS path of the manifest file to parse.
+ * @return an {@link AndroidManifestParser} or null if the parsing failed.
+ * @throws CoreException
+ */
+ public static AndroidManifestParser parseForData(String osManifestFilePath)
+ throws CoreException {
+ return parse(new File(osManifestFilePath));
+ }
+
+ /**
* Returns the package defined in the manifest, if found.
* @return The package name or null if not found.
*/
@@ -633,6 +750,22 @@ public class AndroidManifestParser {
public int getApiLevelRequirement() {
return mApiLevelRequirement;
}
+
+ /**
+ * Returns the list of instrumentations found in the manifest.
+ * @return An array of fully qualified class names, or empty if no instrumentations were found.
+ */
+ public String[] getInstrumentations() {
+ return mInstrumentations;
+ }
+
+ /**
+ * Returns the list of libraries in use found in the manifest.
+ * @return An array of library names, or empty if no uses-library declarations were found.
+ */
+ public String[] getUsesLibraries() {
+ return mLibraries;
+ }
/**
@@ -647,15 +780,92 @@ public class AndroidManifestParser {
* @param processes the list of custom processes declared in the manifest.
* @param debuggable the debuggable attribute, or null if not set.
* @param apiLevelRequirement the minSdkVersion attribute value or 0 if not set.
+ * @param instrumentations the list of instrumentations parsed from the manifest.
+ * @param libraries the list of libraries in use parsed from the manifest.
*/
private AndroidManifestParser(String javaPackage, String[] activities,
String launcherActivity, String[] processes, Boolean debuggable,
- int apiLevelRequirement) {
+ int apiLevelRequirement, String[] instrumentations, String[] libraries) {
mJavaPackage = javaPackage;
mActivities = activities;
mLauncherActivity = launcherActivity;
mProcesses = processes;
mDebuggable = debuggable;
mApiLevelRequirement = apiLevelRequirement;
+ mInstrumentations = instrumentations;
+ mLibraries = libraries;
+ }
+
+ /**
+ * Returns an IFile object representing the manifest for the specified
+ * project.
+ *
+ * @param project The project containing the manifest file.
+ * @return An IFile object pointing to the manifest or null if the manifest
+ * is missing.
+ */
+ public static IFile getManifest(IProject project) {
+ IResource r = project.findMember(AndroidConstants.WS_SEP
+ + AndroidConstants.FN_ANDROID_MANIFEST);
+
+ if (r == null || r.exists() == false || (r instanceof IFile) == false) {
+ return null;
+ }
+ return (IFile) r;
+ }
+
+ /**
+ * Combines a java package, with a class value from the manifest to make a fully qualified
+ * class name
+ * @param javaPackage the java package from the manifest.
+ * @param className the class name from the manifest.
+ * @return the fully qualified class name.
+ */
+ public static String combinePackageAndClassName(String javaPackage, String className) {
+ if (className == null || className.length() == 0) {
+ return javaPackage;
+ }
+ if (javaPackage == null || javaPackage.length() == 0) {
+ return className;
+ }
+
+ // the class name can be a subpackage (starts with a '.'
+ // char), a simple class name (no dot), or a full java package
+ boolean startWithDot = (className.charAt(0) == '.');
+ boolean hasDot = (className.indexOf('.') != -1);
+ if (startWithDot || hasDot == false) {
+
+ // add the concatenation of the package and class name
+ if (startWithDot) {
+ return javaPackage + className;
+ } else {
+ return javaPackage + '.' + className;
+ }
+ } else {
+ // just add the class as it should be a fully qualified java name.
+ return className;
+ }
+ }
+
+ /**
+ * Given a fully qualified activity name (e.g. com.foo.test.MyClass) and given a project
+ * package base name (e.g. com.foo), returns the relative activity name that would be used
+ * the "name" attribute of an "activity" element.
+ *
+ * @param fullActivityName a fully qualified activity class name, e.g. "com.foo.test.MyClass"
+ * @param packageName The project base package name, e.g. "com.foo"
+ * @return The relative activity name if it can be computed or the original fullActivityName.
+ */
+ public static String extractActivityName(String fullActivityName, String packageName) {
+ if (packageName != null && fullActivityName != null) {
+ if (packageName.length() > 0 && fullActivityName.startsWith(packageName)) {
+ String name = fullActivityName.substring(packageName.length());
+ if (name.length() > 0 && name.charAt(0) == '.') {
+ return name;
+ }
+ }
+ }
+
+ return fullActivityName;
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/XmlErrorHandler.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/XmlErrorHandler.java
index fda55c4..1810ad2 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/XmlErrorHandler.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/XmlErrorHandler.java
@@ -86,8 +86,13 @@ public class XmlErrorHandler extends DefaultHandler {
*/
@Override
public void warning(SAXParseException exception) throws SAXException {
- BaseProjectHelper.addMarker(mFile, AndroidConstants.MARKER_XML, exception.getMessage(),
- exception.getLineNumber(), IMarker.SEVERITY_WARNING);
+ if (mFile != null) {
+ BaseProjectHelper.addMarker(mFile,
+ AndroidConstants.MARKER_XML,
+ exception.getMessage(),
+ exception.getLineNumber(),
+ IMarker.SEVERITY_WARNING);
+ }
}
protected final IFile getFile() {
@@ -104,12 +109,19 @@ public class XmlErrorHandler extends DefaultHandler {
mErrorListener.errorFound();
}
- if (lineNumber != -1) {
- BaseProjectHelper.addMarker(mFile, AndroidConstants.MARKER_XML, exception.getMessage(),
- lineNumber, IMarker.SEVERITY_ERROR);
- } else {
- BaseProjectHelper.addMarker(mFile, AndroidConstants.MARKER_XML, exception.getMessage(),
- IMarker.SEVERITY_ERROR);
+ if (mFile != null) {
+ if (lineNumber != -1) {
+ BaseProjectHelper.addMarker(mFile,
+ AndroidConstants.MARKER_XML,
+ exception.getMessage(),
+ lineNumber,
+ IMarker.SEVERITY_ERROR);
+ } else {
+ BaseProjectHelper.addMarker(mFile,
+ AndroidConstants.MARKER_XML,
+ exception.getMessage(),
+ IMarker.SEVERITY_ERROR);
+ }
}
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/AndroidContentAssist.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/AndroidContentAssist.java
index 332ce6f..0d0883e 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/AndroidContentAssist.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/AndroidContentAssist.java
@@ -442,11 +442,15 @@ public abstract class AndroidContentAssist implements IContentAssistProcessor {
tooltip = ((TextAttributeDescriptor) choice).getTooltip();
}
+ // Get the namespace URI for the attribute. Note that some attributes
+ // do not have a namespace and thus return null here.
String nsUri = ((AttributeDescriptor)choice).getNamespaceUri();
- nsPrefix = nsUriMap.get(nsUri);
- if (nsPrefix == null) {
- nsPrefix = lookupNamespacePrefix(currentNode, nsUri);
- nsUriMap.put(nsUri, nsPrefix);
+ if (nsUri != null) {
+ nsPrefix = nsUriMap.get(nsUri);
+ if (nsPrefix == null) {
+ nsPrefix = lookupNamespacePrefix(currentNode, nsUri);
+ nsUriMap.put(nsUri, nsPrefix);
+ }
}
if (nsPrefix != null) {
nsPrefix += ":"; //$NON-NLS-1$
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/ProjectCallback.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/ProjectCallback.java
index 81fd2ed..94ad87a 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/ProjectCallback.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/ProjectCallback.java
@@ -18,12 +18,14 @@ package com.android.ide.eclipse.editors.layout;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.common.AndroidConstants;
-import com.android.ide.eclipse.common.project.AndroidManifestHelper;
+import com.android.ide.eclipse.common.project.AndroidManifestParser;
import com.android.ide.eclipse.editors.resources.manager.ProjectClassLoader;
import com.android.ide.eclipse.editors.resources.manager.ProjectResources;
import com.android.layoutlib.api.IProjectCallback;
+import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.CoreException;
import java.lang.reflect.Constructor;
import java.util.HashMap;
@@ -83,17 +85,20 @@ public final class ProjectCallback implements IProjectCallback {
}
/**
- * {@inheritDoc}
- *
* Returns the namespace for the project. The namespace contains a standard part + the
* application package.
+ *
+ * @return The package namespace of the project or null in case of error.
*/
public String getNamespace() {
if (mNamespace == null) {
- AndroidManifestHelper manifest = new AndroidManifestHelper(mProject);
- String javaPackage = manifest.getPackageName();
-
- mNamespace = String.format(AndroidConstants.NS_CUSTOM_RESOURCES, javaPackage);
+ IFile manifestFile = AndroidManifestParser.getManifest(mProject);
+ try {
+ AndroidManifestParser data = AndroidManifestParser.parseForData(manifestFile);
+ String javaPackage = data.getPackage();
+ mNamespace = String.format(AndroidConstants.NS_CUSTOM_RESOURCES, javaPackage);
+ } catch (CoreException e) {
+ }
}
return mNamespace;
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/descriptors/LayoutDescriptors.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/descriptors/LayoutDescriptors.java
index 7caa50f..c3f4dd8 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/descriptors/LayoutDescriptors.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/descriptors/LayoutDescriptors.java
@@ -17,6 +17,8 @@
package com.android.ide.eclipse.editors.layout.descriptors;
import com.android.ide.eclipse.common.AndroidConstants;
+import com.android.ide.eclipse.common.resources.DeclareStyleableInfo;
+import com.android.ide.eclipse.common.resources.ResourceType;
import com.android.ide.eclipse.common.resources.ViewClassInfo;
import com.android.ide.eclipse.common.resources.DeclareStyleableInfo.AttributeInfo;
import com.android.ide.eclipse.common.resources.ViewClassInfo.LayoutParamsInfo;
@@ -25,6 +27,7 @@ import com.android.ide.eclipse.editors.descriptors.DescriptorsUtils;
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.descriptors.ReferenceAttributeDescriptor;
import com.android.ide.eclipse.editors.descriptors.SeparatorAttributeDescriptor;
import com.android.sdklib.SdkConstants;
@@ -131,8 +134,23 @@ public final class LayoutDescriptors implements IDescriptorProvider {
String xml_name = info.getShortClassName();
String tooltip = info.getJavaDoc();
- // Process all View attributes
ArrayList<AttributeDescriptor> attributes = new ArrayList<AttributeDescriptor>();
+
+ // All views and groups have an implicit "style" attribute which is a reference.
+ AttributeInfo styleInfo = new DeclareStyleableInfo.AttributeInfo(
+ "style", //$NON-NLS-1$ xmlLocalName
+ new DeclareStyleableInfo.AttributeInfo.Format[] {
+ DeclareStyleableInfo.AttributeInfo.Format.REFERENCE
+ });
+ styleInfo.setJavaDoc("A reference to a custom style"); //tooltip
+ DescriptorsUtils.appendAttribute(attributes,
+ "style", //$NON-NLS-1$
+ null, //nsUri
+ styleInfo,
+ false, //required
+ null); // overrides
+
+ // Process all View attributes
DescriptorsUtils.appendAttributes(attributes,
null, // elementName
SdkConstants.NS_RESOURCES,
@@ -155,7 +173,7 @@ public final class LayoutDescriptors implements IDescriptorProvider {
null /* overrides */);
}
}
-
+
// Process all LayoutParams attributes
ArrayList<AttributeDescriptor> layoutAttributes = new ArrayList<AttributeDescriptor>();
LayoutParamsInfo layoutParams = info.getLayoutData();
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/model/UiClassAttributeNode.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/model/UiClassAttributeNode.java
index f886080..e32be86 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/model/UiClassAttributeNode.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/manifest/model/UiClassAttributeNode.java
@@ -17,7 +17,7 @@
package com.android.ide.eclipse.editors.manifest.model;
import com.android.ide.eclipse.common.AndroidConstants;
-import com.android.ide.eclipse.common.project.AndroidManifestHelper;
+import com.android.ide.eclipse.common.project.AndroidManifestParser;
import com.android.ide.eclipse.common.project.BaseProjectHelper;
import com.android.ide.eclipse.editors.AndroidEditor;
import com.android.ide.eclipse.editors.descriptors.AttributeDescriptor;
@@ -251,8 +251,8 @@ public class UiClassAttributeNode extends UiTextAttributeNode {
String javaPackage = getManifestPackage();
// build the fully qualified name of the class
- String className = AndroidManifestHelper.combinePackageAndClassName(javaPackage,
- textValue);
+ String className = AndroidManifestParser.combinePackageAndClassName(
+ javaPackage, textValue);
// only test the vilibility for activities.
boolean testVisibility = AndroidConstants.CLASS_ACTIVITY.equals(
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/CompiledResourcesMonitor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/CompiledResourcesMonitor.java
index 455c825..fa09305 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/CompiledResourcesMonitor.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/manager/CompiledResourcesMonitor.java
@@ -18,7 +18,7 @@ package com.android.ide.eclipse.editors.resources.manager;
import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.common.AndroidConstants;
-import com.android.ide.eclipse.common.project.AndroidManifestHelper;
+import com.android.ide.eclipse.common.project.AndroidManifestParser;
import com.android.ide.eclipse.common.resources.ResourceType;
import com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IFileListener;
import com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IProjectListener;
@@ -28,6 +28,7 @@ import org.eclipse.core.resources.IMarkerDelta;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
@@ -120,7 +121,14 @@ public final class CompiledResourcesMonitor implements IFileListener, IProjectLi
if (projectResources != null) {
// create the classname
String className = getRClassName(project);
-
+ if (className == null) {
+ // We need to abort.
+ AdtPlugin.log(IStatus.ERROR,
+ "loadAndParseRClass: failed to find manifest package for project %1$s", //$NON-NLS-1$
+ project.getName());
+ return;
+ }
+
// create a temporary class loader to load it.
ProjectClassLoader loader = new ProjectClassLoader(null /* parentClassLoader */,
project);
@@ -199,13 +207,28 @@ public final class CompiledResourcesMonitor implements IFileListener, IProjectLi
}
return false;
}
-
+
+ /**
+ * Returns the class name of the R class, based on the project's manifest's package.
+ *
+ * @return A class name (e.g. "my.app.R") or null if there's no valid package in the manifest.
+ */
private String getRClassName(IProject project) {
- // create the classname
- AndroidManifestHelper manifest = new AndroidManifestHelper(project);
- String javaPackage = manifest.getPackageName();
-
- return javaPackage + ".R"; //$NON-NLS-1$
+ try {
+ IFile manifestFile = AndroidManifestParser.getManifest(project);
+ AndroidManifestParser data = AndroidManifestParser.parseForData(manifestFile);
+ String javaPackage = data.getPackage();
+ return javaPackage + ".R"; //$NON-NLS-1$
+ } catch (CoreException e) {
+ // This will typically happen either because the manifest file is not present
+ // and/or the workspace needs to be refreshed.
+ AdtPlugin.logAndPrintError(e,
+ "Android Resources",
+ "Failed to find the package of the AndroidManifest of project %1$s. Reason: %2$s",
+ project.getName(),
+ e.getMessage());
+ return 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 5781938..e84c051 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
@@ -222,10 +222,10 @@ class NewXmlFileCreationPage extends WizardPage {
null, // default attributes
1 // target API level
),
- new TypeInfo("Gadget Provider", // UI name
- "An XML file that describes a gadget provider.", // tooltip
+ new TypeInfo("AppWidget Provider", // UI name
+ "An XML file that describes a widget provider.", // tooltip
ResourceFolderType.XML, // folder type
- AndroidTargetData.DESCRIPTOR_GADGET_PROVIDER, // root seed
+ AndroidTargetData.DESCRIPTOR_APPWIDGET_PROVIDER, // root seed
null, // default root
SdkConstants.NS_RESOURCES, // xmlns
null, // default attributes
@@ -1109,7 +1109,7 @@ class NewXmlFileCreationPage extends WizardPage {
TypeInfo type = getSelectedType();
if (type.getTargetApiLevel() > currentApiLevel) {
- error = "The API level of the selected type (e.g. gadget, etc.) is not " +
+ error = "The API level of the selected type (e.g. AppWidget, etc.) is not " +
"compatible with the API level of the project.";
}
}
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 7929b5a..144b7ac 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,8 +53,8 @@ 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$
+ /** The root document descriptor for widget provider. */
+ private DocumentDescriptor mAppWidgetDescriptor = new DocumentDescriptor("xml_doc", null /* children */); //$NON-NLS-1$
/** @return the root descriptor for both searchable and preferences. */
public DocumentDescriptor getDescriptor() {
@@ -75,9 +75,9 @@ public final class XmlDescriptors implements IDescriptorProvider {
return mPrefDescriptor;
}
- /** @return the root descriptor for gadget providers. */
- public DocumentDescriptor getGadgetDescriptor() {
- return mGadgetDescriptor;
+ /** @return the root descriptor for widget providers. */
+ public DocumentDescriptor getAppWidgetDescriptor() {
+ return mAppWidgetDescriptor;
}
public IDescriptorProvider getSearchableProvider() {
@@ -104,14 +104,14 @@ public final class XmlDescriptors implements IDescriptorProvider {
};
}
- public IDescriptorProvider getGadgetProvider() {
+ public IDescriptorProvider getAppWidgetProvider() {
return new IDescriptorProvider() {
public ElementDescriptor getDescriptor() {
- return mGadgetDescriptor;
+ return mAppWidgetDescriptor;
}
public ElementDescriptor[] getRootElementDescriptors() {
- return mGadgetDescriptor.getChildren();
+ return mAppWidgetDescriptor.getChildren();
}
};
}
@@ -123,13 +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 appWidgetStyleMap The map style=>attributes for <appwidget-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,
+ Map<String, DeclareStyleableInfo> appWidgetStyleMap,
ViewClassInfo[] prefs, ViewClassInfo[] prefGroups) {
XmlnsAttributeDescriptor xmlns = new XmlnsAttributeDescriptor(
@@ -137,16 +137,16 @@ public final class XmlDescriptors implements IDescriptorProvider {
SdkConstants.NS_RESOURCES);
ElementDescriptor searchable = createSearchable(searchableStyleMap, xmlns);
- ElementDescriptor gadget = createGadgetProviderInfo(gadgetStyleMap, xmlns);
+ ElementDescriptor appWidget = createAppWidgetProviderInfo(appWidgetStyleMap, 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 (appWidget != null) {
+ list.add(appWidget);
+ mAppWidgetDescriptor.setChildren(new ElementDescriptor[]{ appWidget });
}
if (preferences != null) {
list.add(preferences);
@@ -190,25 +190,25 @@ public final class XmlDescriptors implements IDescriptorProvider {
}
/**
- * Returns the new ElementDescriptor for <gadget-provider>
+ * Returns the new ElementDescriptor for <appwidget-provider>
*/
- private ElementDescriptor createGadgetProviderInfo(
- Map<String, DeclareStyleableInfo> gadgetStyleMap,
+ private ElementDescriptor createAppWidgetProviderInfo(
+ Map<String, DeclareStyleableInfo> appWidgetStyleMap,
XmlnsAttributeDescriptor xmlns) {
- if (gadgetStyleMap == null) {
+ if (appWidgetStyleMap == null) {
return null;
}
- ElementDescriptor gadget = createElement(gadgetStyleMap,
- "GadgetProviderInfo", //$NON-NLS-1$ styleName
- "gadget-provider", //$NON-NLS-1$ xmlName
- "Gadget Provider", // uiName
+ ElementDescriptor appWidget = createElement(appWidgetStyleMap,
+ "AppWidgetProviderInfo", //$NON-NLS-1$ styleName
+ "appwidget-provider", //$NON-NLS-1$ xmlName
+ "AppWidget Provider", // uiName
null, // sdk url
xmlns, // extraAttribute
null, // childrenElements
false /* mandatory */ );
- return gadget;
+ return appWidget;
}
/**
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/.classpath b/eclipse/plugins/com.android.ide.eclipse.tests/.classpath
index 4088683..6f2a534 100644
--- a/eclipse/plugins/com.android.ide.eclipse.tests/.classpath
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/.classpath
@@ -5,6 +5,6 @@
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="lib" path="kxml2-2.3.0.jar"/>
- <classpathentry combineaccessrules="false" kind="src" path="/SdkLib"/>
+ <classpathentry kind="lib" path="/adt/sdklib.jar" sourcepath="/SdkLib"/>
<classpathentry kind="output" path="bin"/>
</classpath>
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/common/project/AndroidManifestHelperTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/common/project/AndroidManifestHelperTest.java
deleted file mode 100644
index 6604264..0000000
--- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/common/project/AndroidManifestHelperTest.java
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (C) 2007 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.common.project;
-
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-
-import junit.framework.TestCase;
-
-public class AndroidManifestHelperTest extends TestCase {
- private File mFile;
- private AndroidManifestHelper mManifest;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- mFile = File.createTempFile("androidManifest", "xml"); //$NON-NLS-1$ //$NON-NLS-2$
- assertNotNull(mFile);
-
- FileWriter fw = new FileWriter(mFile);
- fw.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"); //$NON-NLS-1$
- fw.write("<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"); //$NON-NLS-1$
- fw.write(" package=\"com.android.testapp\">\n"); //$NON-NLS-1$
- fw.write(" <application android:icon=\"@drawable/icon\">\n"); //$NON-NLS-1$
- fw.write(" <activity android:name=\".MainActivity\" android:label=\"@string/app_name\">\n"); //$NON-NLS-1$
- fw.write(" <intent-filter>\n"); //$NON-NLS-1$
- fw.write(" <action android:name=\"android.intent.action.MAIN\" />\n"); //$NON-NLS-1$
- fw.write(" <category android:name=\"android.intent.category.LAUNCHER\" />\"\n"); //$NON-NLS-1$
- fw.write(" <category android:name=\"android.intent.category.DEFAULT\" />\n"); //$NON-NLS-1$
- fw.write(" </intent-filter>\n"); //$NON-NLS-1$
- fw.write(" </activity>\n"); //$NON-NLS-1$
- fw.write(" <activity android:name=\".OptionsActivity\" android:label=\"@string/options\"\n"); //$NON-NLS-1$
- fw.write(" android:theme=\"@style/Theme.Floating\">\n"); //$NON-NLS-1$
- fw.write(" <intent-filter>\n"); //$NON-NLS-1$
- fw.write(" <action android:name=\"com.android.mandelbrot.action.EDIT_OPTIONS\" />\n"); //$NON-NLS-1$
- fw.write(" <category android:name=\"android.intent.category.PREFERENCE_CATEGORY\" />\n"); //$NON-NLS-1$
- fw.write(" </intent-filter>\n"); //$NON-NLS-1$
- fw.write(" </activity>\n"); //$NON-NLS-1$
- fw.write(" <activity android:name=\".InfoActivity\" android:label=\"@string/options\"\n"); //$NON-NLS-1$
- fw.write(" android:theme=\"@style/Theme.Floating\">\n"); //$NON-NLS-1$
- fw.write(" <intent-filter>\n"); //$NON-NLS-1$
- fw.write(" <action android:name=\"com.android.mandelbrot.action.DISPLAY_INFO\" />\n"); //$NON-NLS-1$
- fw.write(" </intent-filter>\n"); //$NON-NLS-1$
- fw.write(" </activity>\n"); //$NON-NLS-1$
- fw.write(" </application>\n"); //$NON-NLS-1$
- fw.write("</manifest>\n"); //$NON-NLS-1$
- fw.flush();
- fw.close();
-
- mManifest = new AndroidManifestHelper(mFile.getAbsolutePath());
- }
-
- @Override
- protected void tearDown() throws Exception {
- assertTrue(mFile.delete());
- super.tearDown();
- }
-
- public void testExists() {
- assertTrue(mManifest.exists());
- }
-
- public void testNotExists() throws IOException {
- File f = File.createTempFile("androidManifest2", "xml"); //$NON-NLS-1$ //$NON-NLS-2$
- assertTrue(f.delete());
- AndroidManifestHelper manifest = new AndroidManifestHelper(f.getAbsolutePath());
- assertFalse(manifest.exists());
- }
-
- public void testGetPackageName() {
- assertEquals("com.android.testapp", mManifest.getPackageName());
- }
-
- public void testGetActivityName() {
- assertEquals("", mManifest.getActivityName(0)); //$NON-NLS-1$
- assertEquals(".MainActivity", mManifest.getActivityName(1)); //$NON-NLS-1$
- assertEquals(".OptionsActivity", mManifest.getActivityName(2)); //$NON-NLS-1$
- assertEquals(".InfoActivity", mManifest.getActivityName(3)); //$NON-NLS-1$
- assertEquals("", mManifest.getActivityName(4)); //$NON-NLS-1$
- }
-
-}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/common/project/AndroidManifestParserTest.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/common/project/AndroidManifestParserTest.java
new file mode 100644
index 0000000..516e448
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/common/project/AndroidManifestParserTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2007 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.common.project;
+
+import junit.framework.TestCase;
+
+import com.android.ide.eclipse.mock.FileMock;
+
+/**
+ * Tests for {@link AndroidManifestParser}
+ */
+public class AndroidManifestParserTest extends TestCase {
+ private AndroidManifestParser mManifest;
+
+ private static final String PACKAGE_NAME = "com.android.testapp"; //$NON-NLS-1$
+ private static final String ACTIVITY_NAME = "com.android.testapp.MainActivity"; //$NON-NLS-1$
+ private static final String LIBRARY_NAME = "android.test.runner"; //$NON-NLS-1$
+ private static final String INSTRUMENTATION_NAME = "android.test.InstrumentationTestRunner"; //$NON-NLS-1$
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ // create the test data
+ StringBuilder sb = new StringBuilder();
+ sb.append("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"); //$NON-NLS-1$
+ sb.append("<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n"); //$NON-NLS-1$
+ sb.append(" package=\""); //$NON-NLS-1$
+ sb.append(PACKAGE_NAME);
+ sb.append("\">\n"); //$NON-NLS-1$
+ sb.append(" <application android:icon=\"@drawable/icon\">\n"); //$NON-NLS-1$
+ sb.append(" <activity android:name=\""); //$NON-NLS-1$
+ sb.append(ACTIVITY_NAME);
+ sb.append("\" android:label=\"@string/app_name\">\n"); //$NON-NLS-1$
+ sb.append(" <intent-filter>\n"); //$NON-NLS-1$
+ sb.append(" <action android:name=\"android.intent.action.MAIN\" />\n"); //$NON-NLS-1$
+ sb.append(" <category android:name=\"android.intent.category.LAUNCHER\" />\"\n"); //$NON-NLS-1$
+ sb.append(" <category android:name=\"android.intent.category.DEFAULT\" />\n"); //$NON-NLS-1$
+ sb.append(" </intent-filter>\n"); //$NON-NLS-1$
+ sb.append(" </activity>\n"); //$NON-NLS-1$
+ sb.append(" <uses-library android:name=\""); //$NON-NLS-1$
+ sb.append(LIBRARY_NAME);
+ sb.append("\" />\n"); //$NON-NLS-1$
+ sb.append(" </application>"); //$NON-NLS-1$
+ sb.append(" <instrumentation android:name=\""); //$NON-NLS-1$
+ sb.append(INSTRUMENTATION_NAME);
+ sb.append("\"\n");
+ sb.append(" android:targetPackage=\"com.example.android.apis\"\n");
+ sb.append(" android:label=\"Tests for Api Demos.\"/>\n");
+ sb.append("</manifest>\n"); //$NON-NLS-1$
+
+ FileMock mockFile = new FileMock("AndroidManifest.xml", sb.toString().getBytes());
+
+ mManifest = AndroidManifestParser.parseForData(mockFile);
+ assertNotNull(mManifest);
+ }
+
+ public void testGetPackage() {
+ assertEquals("com.android.testapp", mManifest.getPackage());
+ }
+
+ public void testGetActivities() {
+ assertEquals(1, mManifest.getActivities().length);
+ assertEquals(ACTIVITY_NAME, mManifest.getActivities()[0]);
+ }
+
+ public void testGetLauncherActivity() {
+ assertEquals(ACTIVITY_NAME, mManifest.getLauncherActivity());
+ }
+
+ public void testGetUsesLibraries() {
+ assertEquals(1, mManifest.getUsesLibraries().length);
+ assertEquals(LIBRARY_NAME, mManifest.getUsesLibraries()[0]);
+ }
+
+ public void testGetInstrumentations() {
+ assertEquals(1, mManifest.getInstrumentations().length);
+ assertEquals(INSTRUMENTATION_NAME, mManifest.getInstrumentations()[0]);
+ }
+}
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/mock/FileMock.java b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/mock/FileMock.java
index 2220ed1..987ea92 100644
--- a/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/mock/FileMock.java
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/unittests/com/android/ide/eclipse/mock/FileMock.java
@@ -37,6 +37,7 @@ import org.eclipse.core.runtime.jobs.ISchedulingRule;
import sun.reflect.generics.reflectiveObjects.NotImplementedException;
+import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.Reader;
import java.net.URI;
@@ -44,16 +45,28 @@ import java.util.Map;
/**
* Mock implementation of {@link IFile}.
+ *
+ * Optionally backed by an in-memory byte array
+ *
* <p/>Supported methods:
* <ul>
+ * <li>getName()</li>
+ * <li>getContents()</li>
+ * <li>getContents(boolean force)</li>
* </ul>
*/
public class FileMock implements IFile {
private String mName;
+ private byte[] mContentData;
public FileMock(String name) {
+ this(name, new byte[0]);
+ }
+
+ public FileMock(String name, byte[] fileData) {
mName = name;
+ mContentData = fileData;
}
// -------- MOCKED METHODS ----------------
@@ -62,6 +75,15 @@ public class FileMock implements IFile {
return mName;
}
+ public InputStream getContents() throws CoreException {
+ return new ByteArrayInputStream(mContentData);
+ }
+
+ public InputStream getContents(boolean force) throws CoreException {
+ // ignore force
+ return getContents();
+ }
+
// -------- UNIMPLEMENTED METHODS ----------------
public void appendContents(InputStream source, int updateFlags, IProgressMonitor monitor)
@@ -115,14 +137,6 @@ public class FileMock implements IFile {
throw new NotImplementedException();
}
- public InputStream getContents() throws CoreException {
- throw new NotImplementedException();
- }
-
- public InputStream getContents(boolean force) throws CoreException {
- throw new NotImplementedException();
- }
-
public int getEncoding() throws CoreException {
throw new NotImplementedException();
}
@@ -139,7 +153,8 @@ public class FileMock implements IFile {
throw new NotImplementedException();
}
- public void move(IPath destination, boolean force, boolean keepHistory, IProgressMonitor monitor)
+ public void move(IPath destination, boolean force, boolean keepHistory,
+ IProgressMonitor monitor)
throws CoreException {
throw new NotImplementedException();
}
@@ -229,7 +244,8 @@ public class FileMock implements IFile {
throw new NotImplementedException();
}
- public void deleteMarkers(String type, boolean includeSubtypes, int depth) throws CoreException {
+ public void deleteMarkers(String type, boolean includeSubtypes, int depth)
+ throws CoreException {
throw new NotImplementedException();
}
@@ -424,26 +440,26 @@ public class FileMock implements IFile {
throw new NotImplementedException();
}
- @SuppressWarnings("unchecked")
+ @SuppressWarnings("unchecked")
public Map getPersistentProperties() throws CoreException {
throw new NotImplementedException();
- }
+ }
- @SuppressWarnings("unchecked")
+ @SuppressWarnings("unchecked")
public Map getSessionProperties() throws CoreException {
throw new NotImplementedException();
- }
+ }
- public boolean isDerived(int options) {
+ public boolean isDerived(int options) {
throw new NotImplementedException();
- }
+ }
- public boolean isHidden() {
+ public boolean isHidden() {
throw new NotImplementedException();
- }
+ }
- public void setHidden(boolean isHidden) throws CoreException {
+ public void setHidden(boolean isHidden) throws CoreException {
throw new NotImplementedException();
- }
-
+ }
}
+
diff --git a/emulator/keymaps/AVRCP.kl b/emulator/keymaps/AVRCP.kl
new file mode 100644
index 0000000..175824e
--- /dev/null
+++ b/emulator/keymaps/AVRCP.kl
@@ -0,0 +1,7 @@
+key 164 PLAYPAUSE WAKE
+key 128 STOP WAKE
+key 163 NEXTSONG WAKE
+key 165 PREVIOUSSONG WAKE
+key 168 REWIND WAKE
+key 159 FORWARD WAKE
+
diff --git a/emulator/keymaps/Android.mk b/emulator/keymaps/Android.mk
index 90db52e..81ac530 100644
--- a/emulator/keymaps/Android.mk
+++ b/emulator/keymaps/Android.mk
@@ -11,3 +11,8 @@ file := $(TARGET_OUT_KEYLAYOUT)/qwerty.kl
ALL_PREBUILT += $(file)
$(file): $(LOCAL_PATH)/qwerty.kl | $(ACP)
$(transform-prebuilt-to-target)
+
+file := $(TARGET_OUT_KEYLAYOUT)/AVRCP.kl
+ALL_PREBUILT += $(file)
+$(file) : $(LOCAL_PATH)/AVRCP.kl | $(ACP)
+ $(transform-prebuilt-to-target)
diff --git a/hierarchyviewer/src/com/android/hierarchyviewer/scene/ProfilesLoader.java b/hierarchyviewer/src/com/android/hierarchyviewer/scene/ProfilesLoader.java
new file mode 100644
index 0000000..83b9113
--- /dev/null
+++ b/hierarchyviewer/src/com/android/hierarchyviewer/scene/ProfilesLoader.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.hierarchyviewer.scene;
+
+import com.android.ddmlib.Device;
+import com.android.hierarchyviewer.device.Window;
+import com.android.hierarchyviewer.device.DeviceBridge;
+
+import java.net.Socket;
+import java.net.InetSocketAddress;
+import java.io.BufferedWriter;
+import java.io.OutputStreamWriter;
+import java.io.IOException;
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+
+public class ProfilesLoader {
+ public static double[] loadProfiles(Device device, Window window, String params) {
+ Socket socket = null;
+ BufferedReader in = null;
+ BufferedWriter out = null;
+
+ try {
+ socket = new Socket();
+ socket.connect(new InetSocketAddress("127.0.0.1",
+ DeviceBridge.getDeviceLocalPort(device)));
+
+ out = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
+ in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+
+ out.write("PROFILE " + window.encode() + " " + params);
+ out.newLine();
+ out.flush();
+
+ String response = in.readLine();
+ String[] data = response.split(" ");
+
+ double[] profiles = new double[data.length];
+ for (int i = 0; i < data.length; i++) {
+ profiles[i] = (Long.parseLong(data[i]) / 1000.0) / 1000.0; // convert to ms
+ }
+ return profiles;
+ } catch (IOException e) {
+ // Empty
+ } finally {
+ try {
+ if (out != null) {
+ out.close();
+ }
+ if (in != null) {
+ in.close();
+ }
+ if (socket != null) {
+ socket.close();
+ }
+ } catch (IOException ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ return null;
+ }
+}
diff --git a/hierarchyviewer/src/com/android/hierarchyviewer/ui/Workspace.java b/hierarchyviewer/src/com/android/hierarchyviewer/ui/Workspace.java
index 77ebb39..d530c35 100644
--- a/hierarchyviewer/src/com/android/hierarchyviewer/ui/Workspace.java
+++ b/hierarchyviewer/src/com/android/hierarchyviewer/ui/Workspace.java
@@ -27,6 +27,7 @@ import com.android.hierarchyviewer.scene.ViewHierarchyScene;
import com.android.hierarchyviewer.scene.ViewManager;
import com.android.hierarchyviewer.scene.ViewNode;
import com.android.hierarchyviewer.scene.WindowsLoader;
+import com.android.hierarchyviewer.scene.ProfilesLoader;
import com.android.hierarchyviewer.util.OS;
import com.android.hierarchyviewer.util.WorkerThread;
import com.android.hierarchyviewer.ui.action.ShowDevicesAction;
@@ -43,6 +44,7 @@ import com.android.hierarchyviewer.ui.util.PngFileFilter;
import com.android.hierarchyviewer.ui.util.IconLoader;
import com.android.hierarchyviewer.ui.model.PropertiesTableModel;
import com.android.hierarchyviewer.ui.model.ViewsTreeModel;
+import com.android.hierarchyviewer.ui.model.ProfilesTableModel;
import org.jdesktop.swingworker.SwingWorker;
import org.netbeans.api.visual.graph.layout.TreeGraphLayout;
import org.netbeans.api.visual.model.ObjectSceneEvent;
@@ -123,6 +125,7 @@ public class Workspace extends JFrame {
private JSplitPane sideSplitter;
private JSplitPane mainSplitter;
private JTable propertiesTable;
+ private JTable profilingTable;
private JComponent pixelPerfectPanel;
private JTree pixelPerfectTree;
private ScreenViewer screenViewer;
@@ -274,11 +277,32 @@ public class Workspace extends JFrame {
JScrollPane tableScroller = new JScrollPane(propertiesTable);
tableScroller.setBorder(null);
+ profilingTable = new JTable();
+ profilingTable.setModel(new DefaultTableModel(new Object[][] {
+ { " " , " " }, { " " , " " }, { " " , " " } },
+ new String[] { "Operation", "Duration (ms)" }));
+ profilingTable.setBorder(null);
+ profilingTable.getTableHeader().setBorder(null);
+
+ JScrollPane firstTableScroller = new JScrollPane(profilingTable);
+ firstTableScroller.setBorder(null);
+
+ setVisibleRowCount(profilingTable, 5);
+ firstTableScroller.setMinimumSize(profilingTable.getPreferredScrollableViewportSize());
+
+ JSplitPane tablesSplitter = new JSplitPane();
+ tablesSplitter.setBorder(null);
+ tablesSplitter.setOrientation(JSplitPane.VERTICAL_SPLIT);
+ tablesSplitter.setResizeWeight(0);
+ tablesSplitter.setLeftComponent(firstTableScroller);
+ tablesSplitter.setBottomComponent(tableScroller);
+ tablesSplitter.setContinuousLayout(true);
+
sideSplitter = new JSplitPane();
sideSplitter.setBorder(null);
sideSplitter.setOrientation(JSplitPane.VERTICAL_SPLIT);
sideSplitter.setResizeWeight(0.5);
- sideSplitter.setLeftComponent(tableScroller);
+ sideSplitter.setLeftComponent(tablesSplitter);
sideSplitter.setBottomComponent(null);
sideSplitter.setContinuousLayout(true);
@@ -603,6 +627,22 @@ public class Workspace extends JFrame {
propertiesTable.setModel(new PropertiesTableModel(node));
}
+ private void updateProfiles(double[] profiles) {
+ profilingTable.setModel(new ProfilesTableModel(profiles));
+ setVisibleRowCount(profilingTable, profiles.length + 1);
+ }
+
+ public static void setVisibleRowCount(JTable table, int rows) {
+ int height = 0;
+ for (int row = 0; row < rows; row++) {
+ height += table.getRowHeight(row);
+ }
+
+ Dimension size = new Dimension(table.getPreferredScrollableViewportSize().width, height);
+ table.setPreferredScrollableViewportSize(size);
+ table.revalidate();
+ }
+
private void showPixelPerfectTree() {
if (pixelPerfectTree == null) {
return;
@@ -1134,22 +1174,24 @@ public class Workspace extends JFrame {
}
}
- private class LoadGraphTask extends SwingWorker<ViewHierarchyScene, Void> {
+ private class LoadGraphTask extends SwingWorker<double[], Void> {
public LoadGraphTask() {
beginTask();
}
@Override
@WorkerThread
- protected ViewHierarchyScene doInBackground() {
+ protected double[] doInBackground() {
scene = ViewHierarchyLoader.loadScene(currentDevice, currentWindow);
- return scene;
+ return ProfilesLoader.loadProfiles(currentDevice, currentWindow,
+ scene.getRoot().toString());
}
@Override
protected void done() {
try {
- createGraph(get());
+ createGraph(scene);
+ updateProfiles(get());
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
diff --git a/hierarchyviewer/src/com/android/hierarchyviewer/ui/model/ProfilesTableModel.java b/hierarchyviewer/src/com/android/hierarchyviewer/ui/model/ProfilesTableModel.java
new file mode 100644
index 0000000..fcbe6b5
--- /dev/null
+++ b/hierarchyviewer/src/com/android/hierarchyviewer/ui/model/ProfilesTableModel.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.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.apache.org/licenses/LICENSE-2.0
+ *
+ * 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.hierarchyviewer.ui.model;
+
+import javax.swing.table.DefaultTableModel;
+import java.text.NumberFormat;
+
+public class ProfilesTableModel extends DefaultTableModel {
+ private static final String[] NAMES = { "measure", "layout", "draw" };
+
+ private final double[] profiles;
+ private final NumberFormat formatter;
+
+ public ProfilesTableModel(double[] profiles) {
+ this.profiles = profiles;
+ formatter = NumberFormat.getNumberInstance();
+ }
+
+ @Override
+ public int getRowCount() {
+ return profiles == null ? 0 : profiles.length;
+ }
+
+ @Override
+ public Object getValueAt(int row, int column) {
+ if (profiles == null) return "";
+
+ if (column == 0) {
+ return NAMES[row];
+ }
+
+
+ return formatter.format(profiles[row]) + "";
+ }
+
+ @Override
+ public int getColumnCount() {
+ return 2;
+ }
+
+ @Override
+ public String getColumnName(int column) {
+ return column == 0 ? "Operation" : "Duration (ms)";
+ }
+
+ @Override
+ public boolean isCellEditable(int arg0, int arg1) {
+ return false;
+ }
+
+ @Override
+ public void setValueAt(Object arg0, int arg1, int arg2) {
+ }
+}
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java
index 7b8fdbe..65cbbe3 100644
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java
@@ -303,8 +303,11 @@ public final class AvdManager {
}
if (NUMERIC_SKIN_SIZE.matcher(skinName).matches()) {
- // Skin name is an actual screen resolution, no skin.path
+ // Skin name is an actual screen resolution.
+ // Set skin.name for display purposes in the AVD manager and
+ // set skin.path for use by the emulator.
values.put(AVD_INI_SKIN_NAME, skinName);
+ values.put(AVD_INI_SKIN_PATH, skinName);
} else {
// get the path of the skin (relative to the SDK)
// assume skin name is valid
diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/ApkConfigWidget.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/ApkConfigWidget.java
index 6bf1df3..825be93 100644
--- a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/ApkConfigWidget.java
+++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/ApkConfigWidget.java
@@ -41,7 +41,7 @@ import java.util.Set;
* The APK Configuration widget is a table that is added to the given parent composite.
* <p/>
* To use, create it using {@link #ApkConfigWidget(Composite)} then
- * call {@link #fillTable(Map) to set the initial list of configurations.
+ * call {@link #fillTable(Map)} to set the initial list of configurations.
*/
public class ApkConfigWidget {
private final static int INDEX_NAME = 0;
diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/AvdSelector.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/AvdSelector.java
index 9d0b928..67c70a6 100644
--- a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/AvdSelector.java
+++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/AvdSelector.java
@@ -36,21 +36,17 @@ import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
-import java.util.ArrayList;
-
/**
* The AVD selector is a table that is added to the given parent composite.
* <p/>
- * To use, create it using {@link #AvdSelector(Composite, AvdInfo[], boolean)} then
+ * To use, create it using {@link #AvdSelector(Composite, AvdInfo[])} then
* call {@link #setSelection(AvdInfo)}, {@link #setSelectionListener(SelectionListener)}
- * and finally use {@link #getFirstSelected()} or {@link #getAllSelected()} to retrieve the
- * selection.
+ * and finally use {@link #getFirstSelected()} to retrieve the selection.
*/
public final class AvdSelector {
private AvdInfo[] mAvds;
- private final boolean mAllowMultipleSelection;
private SelectionListener mSelectionListener;
private Table mTable;
private Label mDescription;
@@ -63,11 +59,8 @@ public final class AvdSelector {
*
* @param parent The parent composite where the selector will be added.
* @param avds The list of AVDs. This is <em>not</em> copied, the caller must not modify.
- * @param allowMultipleSelection True if more than one SDK target can be selected at the same
- * time.
*/
- public AvdSelector(Composite parent, AvdInfo[] avds, IAndroidTarget filter,
- boolean allowMultipleSelection) {
+ public AvdSelector(Composite parent, AvdInfo[] avds, IAndroidTarget filter) {
mAvds = avds;
// Layout has 1 column
@@ -76,7 +69,6 @@ public final class AvdSelector {
group.setLayoutData(new GridData(GridData.FILL_BOTH));
group.setFont(parent.getFont());
- mAllowMultipleSelection = allowMultipleSelection;
mTable = new Table(group, SWT.CHECK | SWT.FULL_SELECTION | SWT.SINGLE | SWT.BORDER);
mTable.setHeaderVisible(true);
mTable.setLinesVisible(false);
@@ -112,11 +104,9 @@ public final class AvdSelector {
*
* @param parent The parent composite where the selector will be added.
* @param avds The list of AVDs. This is <em>not</em> copied, the caller must not modify.
- * @param allowMultipleSelection True if more than one SDK target can be selected at the same
- * time.
*/
- public AvdSelector(Composite parent, AvdInfo[] avds, boolean allowMultipleSelection) {
- this(parent, avds, null /* filter */, allowMultipleSelection);
+ public AvdSelector(Composite parent, AvdInfo[] avds) {
+ this(parent, avds, null /* filter */);
}
@@ -160,8 +150,7 @@ public final class AvdSelector {
* The event's item contains a {@link TableItem}.
* The {@link TableItem#getData()} contains an {@link IAndroidTarget}.
* <p/>
- * It is recommended that the caller uses the {@link #getFirstSelected()} and
- * {@link #getAllSelected()} methods instead.
+ * It is recommended that the caller uses the {@link #getFirstSelected()} method instead.
*
* @param selectionListener The new listener or null to remove it.
*/
@@ -202,27 +191,9 @@ public final class AvdSelector {
}
/**
- * Returns all selected items.
- * This is useful when the table is in multiple-selection mode.
- *
- * @see #getFirstSelected()
- * @return An array of selected items. The list can be empty but not null.
- */
- public AvdInfo[] getAllSelected() {
- ArrayList<IAndroidTarget> list = new ArrayList<IAndroidTarget>();
- for (TableItem i : mTable.getItems()) {
- if (i.getChecked()) {
- list.add((IAndroidTarget) i.getData());
- }
- }
- return list.toArray(new AvdInfo[list.size()]);
- }
-
- /**
* Returns the first selected item.
* This is useful when the table is in single-selection mode.
*
- * @see #getAllSelected()
* @return The first selected item or null.
*/
public AvdInfo getFirstSelected() {
@@ -278,38 +249,50 @@ public final class AvdSelector {
private void setupSelectionListener(final Table table) {
// Add a selection listener that will check/uncheck items when they are double-clicked
table.addSelectionListener(new SelectionListener() {
- /** Default selection means double-click on "most" platforms */
- public void widgetDefaultSelected(SelectionEvent e) {
+
+ /**
+ * Handles single-click selection on the table.
+ * {@inheritDoc}
+ */
+ public void widgetSelected(SelectionEvent e) {
if (e.item instanceof TableItem) {
TableItem i = (TableItem) e.item;
- i.setChecked(!i.getChecked());
enforceSingleSelection(i);
updateDescription(i);
}
if (mSelectionListener != null) {
- mSelectionListener.widgetDefaultSelected(e);
+ mSelectionListener.widgetSelected(e);
}
}
-
- public void widgetSelected(SelectionEvent e) {
+
+ /**
+ * Handles double-click selection on the table.
+ * Note that the single-click handler will probably already have been called.
+ *
+ * On double-click, <em>always</em> check the table item.
+ *
+ * {@inheritDoc}
+ */
+ public void widgetDefaultSelected(SelectionEvent e) {
if (e.item instanceof TableItem) {
TableItem i = (TableItem) e.item;
+ i.setChecked(true);
enforceSingleSelection(i);
updateDescription(i);
}
if (mSelectionListener != null) {
- mSelectionListener.widgetSelected(e);
+ mSelectionListener.widgetDefaultSelected(e);
}
}
/**
- * If we're not in multiple selection mode, uncheck all other
- * items when this one is selected.
+ * To ensure single selection, uncheck all other items when this one is selected.
+ * This makes the chekboxes act as radio buttons.
*/
private void enforceSingleSelection(TableItem item) {
- if (!mAllowMultipleSelection && item.getChecked()) {
+ if (item.getChecked()) {
Table parentTable = item.getParent();
for (TableItem i2 : parentTable.getItems()) {
if (i2 != item && i2.getChecked()) {