diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AndroidLaunchController.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AndroidLaunchController.java
index 655c038e1..7ee3def57 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AndroidLaunchController.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AndroidLaunchController.java
@@ -1078,7 +1078,7 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
/**
* Performs the installation of an application whose package has been uploaded on the device.
- *
Before doing it, if the application is already running on the device, it is killed.
+ *
* @param launchInfo the {@link DelayedLaunchInfo}.
* @param remotePath the path of the application package in the device tmp folder.
* @param device the device on which to install the application.
@@ -1088,12 +1088,6 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
*/
private String doInstall(DelayedLaunchInfo launchInfo, final String remotePath,
final IDevice device, boolean reinstall) throws IOException {
- // kill running application
- Client application = device.getClient(launchInfo.getPackageName());
- if (application != null) {
- application.kill();
- }
-
InstallReceiver receiver = new InstallReceiver();
try {
String cmd = String.format(
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/LaunchConfigDelegate.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/LaunchConfigDelegate.java
index 9f12b16e4..4fa270e4e 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/LaunchConfigDelegate.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/LaunchConfigDelegate.java
@@ -23,6 +23,7 @@ import com.android.ide.eclipse.adt.project.ProjectHelper;
import com.android.ide.eclipse.common.AndroidConstants;
import com.android.ide.eclipse.common.project.AndroidManifestParser;
import com.android.ide.eclipse.common.project.BaseProjectHelper;
+import com.android.ide.eclipse.common.project.AndroidManifestParser.Activity;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
@@ -247,7 +248,7 @@ public class LaunchConfigDelegate extends LaunchConfigurationDelegate {
activityName = getActivityName(configuration);
// Get the full activity list and make sure the one we got matches.
- String[] activities = manifestParser.getActivities();
+ Activity[] activities = manifestParser.getActivities();
// first we check that there are, in fact, activities.
if (activities.length == 0) {
@@ -261,8 +262,11 @@ public class LaunchConfigDelegate extends LaunchConfigurationDelegate {
// if the activity we got is null, we look for the default one.
AdtPlugin.printErrorToConsole(project,
"No activity specified! Getting the launcher activity.");
- activityName = manifestParser.getLauncherActivity();
-
+ Activity launcherActivity = manifestParser.getLauncherActivity();
+ if (launcherActivity != null) {
+ activityName = launcherActivity.getName();
+ }
+
// if there's no default activity. We revert to a sync-only launch.
if (activityName == null) {
revertToNoActionLaunch(project, config);
@@ -271,8 +275,8 @@ public class LaunchConfigDelegate extends LaunchConfigurationDelegate {
// check the one we got from the config matches any from the list
boolean match = false;
- for (String a : activities) {
- if (a != null && a.equals(activityName)) {
+ for (Activity a : activities) {
+ if (a != null && a.getName().equals(activityName)) {
match = true;
break;
}
@@ -282,7 +286,10 @@ public class LaunchConfigDelegate extends LaunchConfigurationDelegate {
if (match == false) {
AdtPlugin.printErrorToConsole(project,
"The specified activity does not exist! Getting the launcher activity.");
- activityName = manifestParser.getLauncherActivity();
+ Activity launcherActivity = manifestParser.getLauncherActivity();
+ if (launcherActivity != null) {
+ activityName = launcherActivity.getName();
+ }
// if there's no default activity. We revert to a sync-only launch.
if (activityName == null) {
@@ -291,7 +298,10 @@ public class LaunchConfigDelegate extends LaunchConfigurationDelegate {
}
}
} else if (config.mLaunchAction == ACTION_DEFAULT) {
- activityName = manifestParser.getLauncherActivity();
+ Activity launcherActivity = manifestParser.getLauncherActivity();
+ if (launcherActivity != null) {
+ activityName = launcherActivity.getName();
+ }
// if there's no default activity. We revert to a sync-only launch.
if (activityName == null) {
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/MainLaunchConfigTab.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/MainLaunchConfigTab.java
index 91bd21cb7..a32c2ee0e 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/MainLaunchConfigTab.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/MainLaunchConfigTab.java
@@ -20,6 +20,7 @@ import com.android.ide.eclipse.adt.AdtPlugin;
import com.android.ide.eclipse.common.project.AndroidManifestParser;
import com.android.ide.eclipse.common.project.BaseProjectHelper;
import com.android.ide.eclipse.common.project.ProjectChooserHelper;
+import com.android.ide.eclipse.common.project.AndroidManifestParser.Activity;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
@@ -50,6 +51,8 @@ import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Text;
+import java.util.ArrayList;
+
/**
* Class for the main launch configuration tab.
*/
@@ -66,7 +69,7 @@ public class MainLaunchConfigTab extends AbstractLaunchConfigurationTab {
private Button mProjButton;
private Combo mActivityCombo;
- private String[] mActivities;
+ private final ArrayList mActivities = new ArrayList();
private WidgetListener mListener = new WidgetListener();
@@ -214,8 +217,9 @@ public class MainLaunchConfigTab extends AbstractLaunchConfigurationTab {
// add the activity
int selection = mActivityCombo.getSelectionIndex();
- if (mActivities != null && selection >=0 && selection < mActivities.length) {
- configuration.setAttribute(LaunchConfigDelegate.ATTR_ACTIVITY, mActivities[selection]);
+ if (mActivities != null && selection >=0 && selection < mActivities.size()) {
+ configuration.setAttribute(LaunchConfigDelegate.ATTR_ACTIVITY,
+ mActivities.get(selection).getName());
}
// link the project and the launch config.
@@ -349,11 +353,11 @@ public class MainLaunchConfigTab extends AbstractLaunchConfigurationTab {
mActivityCombo.setEnabled(true);
if (activityName == null || activityName.equals(EMPTY_STRING)) {
mActivityCombo.clearSelection();
- } else if (mActivities != null && mActivities.length > 0) {
+ } else if (mActivities != null && mActivities.size() > 0) {
// look for the name of the activity in the combo.
boolean found = false;
- for (int i = 0 ; i < mActivities.length ; i++) {
- if (activityName.equals(mActivities[i])) {
+ for (int i = 0 ; i < mActivities.size() ; i++) {
+ if (activityName.equals(mActivities.get(i).getName())) {
found = true;
mActivityCombo.select(i);
break;
@@ -404,17 +408,22 @@ public class MainLaunchConfigTab extends AbstractLaunchConfigurationTab {
BaseProjectHelper.getJavaProject(project), null /* errorListener */,
true /* gatherData */, false /* markErrors */);
if (manifestParser != null) {
- mActivities = manifestParser.getActivities();
-
+ Activity[] activities = manifestParser.getActivities();
+
+ mActivities.clear();
mActivityCombo.removeAll();
-
- if (mActivities.length > 0) {
+
+ for (Activity activity : activities) {
+ if (activity.getExported() && activity.hasAction()) {
+ mActivities.add(activity);
+ mActivityCombo.add(activity.getName());
+ }
+ }
+
+ if (mActivities.size() > 0) {
if (mLaunchAction == LaunchConfigDelegate.ACTION_ACTIVITY) {
mActivityCombo.setEnabled(true);
}
- for (String s : mActivities) {
- mActivityCombo.add(s);
- }
} else {
mActivityCombo.setEnabled(false);
}
@@ -435,7 +444,7 @@ public class MainLaunchConfigTab extends AbstractLaunchConfigurationTab {
// if we reach this point, either project is null, or we got an exception during
// the parsing. In either case, we empty the activity list.
mActivityCombo.removeAll();
- mActivities = null;
+ mActivities.clear();
}
/**
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectCreationPage.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectCreationPage.java
index e26b31cc3..6e8ff47fe 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectCreationPage.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectCreationPage.java
@@ -27,6 +27,7 @@ import com.android.ide.eclipse.adt.sdk.Sdk;
import com.android.ide.eclipse.adt.sdk.Sdk.ITargetChangeListener;
import com.android.ide.eclipse.common.AndroidConstants;
import com.android.ide.eclipse.common.project.AndroidManifestParser;
+import com.android.ide.eclipse.common.project.AndroidManifestParser.Activity;
import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.SdkConstants;
import com.android.sdklib.project.ProjectProperties;
@@ -859,6 +860,7 @@ public class NewProjectCreationPage extends WizardPage {
}
String packageName = null;
+ Activity activity = null;
String activityName = null;
int minSdkVersion = AndroidManifestParser.INVALID_MIN_SDK;
try {
@@ -866,11 +868,11 @@ public class NewProjectCreationPage extends WizardPage {
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();
+ activity = manifestData.getLauncherActivity();
+ if (activity == null) {
+ Activity[] activities = manifestData.getActivities();
if (activities != null && activities.length > 0) {
- activityName = activities[0];
+ activity = activities[0];
}
}
} catch (Exception e) {
@@ -881,7 +883,10 @@ public class NewProjectCreationPage extends WizardPage {
mPackageNameField.setText(packageName);
}
- activityName = AndroidManifestParser.extractActivityName(activityName, packageName);
+ if (activity != null) {
+ activityName = AndroidManifestParser.extractActivityName(activity.getName(),
+ packageName);
+ }
if (activityName != null && activityName.length() > 0) {
mInternalActivityNameUpdate = true;
@@ -1136,7 +1141,7 @@ public class NewProjectCreationPage extends WizardPage {
MSG_ERROR);
}
- String[] activities = manifestData.getActivities();
+ Activity[] activities = manifestData.getActivities();
if (activities == null || activities.length == 0) {
// This is acceptable now as long as no activity needs to be created
if (isCreateActivity()) {
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java
index f853adacb..69982fc66 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/project/AndroidManifestParser.java
@@ -53,6 +53,7 @@ public class AndroidManifestParser {
private final static String ATTRIBUTE_DEBUGGABLE = "debuggable"; //$NON-NLS-$
private final static String ATTRIBUTE_MIN_SDK_VERSION = "minSdkVersion"; //$NON-NLS-$
private final static String ATTRIBUTE_TARGET_PACKAGE = "targetPackage"; //$NON-NLS-1$
+ private final static String ATTRIBUTE_EXPORTED = "exported"; //$NON-NLS-1$
private final static String NODE_MANIFEST = "manifest"; //$NON-NLS-1$
private final static String NODE_APPLICATION = "application"; //$NON-NLS-1$
private final static String NODE_ACTIVITY = "activity"; //$NON-NLS-1$
@@ -84,7 +85,7 @@ public class AndroidManifestParser {
private final String mName;
private final String mTargetPackage;
- public Instrumentation(String name, String targetPackage) {
+ Instrumentation(String name, String targetPackage) {
mName = name;
mTargetPackage = targetPackage;
}
@@ -104,6 +105,60 @@ public class AndroidManifestParser {
}
}
+ /**
+ * Activity info obtained from the manifest.
+ */
+ public static class Activity {
+ private final String mName;
+ private final boolean mExported;
+ private boolean mHasAction = false;
+ private boolean mHasMainAction = false;
+ private boolean mHasLauncherCategory = false;
+
+ public Activity(String name, boolean exported) {
+ mName = name;
+ mExported = exported;
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ public boolean getExported() {
+ return mExported;
+ }
+
+ public boolean hasAction() {
+ return mHasAction;
+ }
+
+ public boolean isHomeActivity() {
+ return mHasMainAction && mHasLauncherCategory;
+ }
+
+ void setHasAction(boolean hasAction) {
+ mHasAction = hasAction;
+ }
+
+ /** If the activity doesn't yet have a filter set for the launcher, this resets both
+ * flags. This is to handle multiple intent-filters where one could have the valid
+ * action, and another one of the valid category.
+ */
+ void resetIntentFilter() {
+ if (isHomeActivity() == false) {
+ mHasMainAction = mHasLauncherCategory = false;
+ }
+ }
+
+ void setHasMainAction(boolean hasMainAction) {
+ mHasMainAction = hasMainAction;
+ }
+
+ void setHasLauncherCategory(boolean hasLauncherCategory) {
+ mHasLauncherCategory = hasLauncherCategory;
+ }
+ }
+
/**
* XML error & data handler used when parsing the AndroidManifest.xml file.
*
@@ -117,9 +172,9 @@ public class AndroidManifestParser {
/** Application package */
private String mPackage;
/** List of all activities */
- private final ArrayList mActivities = new ArrayList();
+ private final ArrayList mActivities = new ArrayList();
/** Launcher activity */
- private String mLauncherActivity = null;
+ private Activity mLauncherActivity = null;
/** list of process names declared by the manifest */
private Set mProcesses = null;
/** debuggable attribute value. If null, the attribute is not present. */
@@ -139,9 +194,7 @@ public class AndroidManifestParser {
private boolean mMarkErrors = false;
private int mCurrentLevel = 0;
private int mValidLevel = 0;
- private boolean mFoundMainAction = false;
- private boolean mFoundLauncherCategory = false;
- private String mCurrentActivity = null;
+ private Activity mCurrentActivity = null;
private Locator mLocator;
/**
@@ -173,8 +226,8 @@ public class AndroidManifestParser {
* Returns the list of activities found in the manifest.
* @return An array of fully qualified class names, or empty if no activity were found.
*/
- String[] getActivities() {
- return mActivities.toArray(new String[mActivities.size()]);
+ Activity[] getActivities() {
+ return mActivities.toArray(new Activity[mActivities.size()]);
}
/**
@@ -182,7 +235,7 @@ public class AndroidManifestParser {
* up in the HOME screen.
* @return the fully qualified name of a HOME activity or null if none were found.
*/
- String getLauncherActivity() {
+ Activity getLauncherActivity() {
return mLauncherActivity;
}
@@ -314,27 +367,26 @@ public class AndroidManifestParser {
case LEVEL_INTENT_FILTER:
// only process this level if we are in an activity
if (mCurrentActivity != null && NODE_INTENT.equals(localName)) {
- // if we're at the intent level, lets reset some flag to
- // be used when parsing the children
- mFoundMainAction = false;
- mFoundLauncherCategory = false;
+ mCurrentActivity.resetIntentFilter();
mValidLevel++;
}
break;
case LEVEL_CATEGORY:
- if (mCurrentActivity != null && mLauncherActivity == null) {
+ if (mCurrentActivity != null) {
if (NODE_ACTION.equals(localName)) {
// get the name attribute
- if (ACTION_MAIN.equals(
- getAttributeValue(attributes, ATTRIBUTE_NAME,
- true /* hasNamespace */))) {
- mFoundMainAction = true;
+ String action = getAttributeValue(attributes, ATTRIBUTE_NAME,
+ true /* hasNamespace */);
+ if (action != null) {
+ mCurrentActivity.setHasAction(true);
+ mCurrentActivity.setHasMainAction(
+ ACTION_MAIN.equals(action));
}
} else if (NODE_CATEGORY.equals(localName)) {
- if (CATEGORY_LAUNCHER.equals(
- getAttributeValue(attributes, ATTRIBUTE_NAME,
- true /* hasNamespace */))) {
- mFoundLauncherCategory = true;
+ String category = getAttributeValue(attributes, ATTRIBUTE_NAME,
+ true /* hasNamespace */);
+ if (CATEGORY_LAUNCHER.equals(category)) {
+ mCurrentActivity.setHasLauncherCategory(true);
}
}
@@ -378,8 +430,7 @@ public class AndroidManifestParser {
case LEVEL_INTENT_FILTER:
// if we found both a main action and a launcher category, this is our
// launcher activity!
- if (mCurrentActivity != null &&
- mFoundMainAction && mFoundLauncherCategory) {
+ if (mCurrentActivity != null && mCurrentActivity.isHomeActivity()) {
mLauncherActivity = mCurrentActivity;
}
break;
@@ -432,17 +483,23 @@ public class AndroidManifestParser {
String activityName = getAttributeValue(attributes, ATTRIBUTE_NAME,
true /* hasNamespace */);
if (activityName != null) {
- mCurrentActivity = combinePackageAndClassName(mPackage, activityName);
+ activityName = combinePackageAndClassName(mPackage, activityName);
+
+ // get the exported flag.
+ String exportedStr = getAttributeValue(attributes, ATTRIBUTE_EXPORTED, true);
+ boolean exported = exportedStr == null ||
+ exportedStr.toLowerCase().equals("true"); // $NON-NLS-1$
+ mCurrentActivity = new Activity(activityName, exported);
mActivities.add(mCurrentActivity);
if (mMarkErrors) {
- checkClass(mCurrentActivity, AndroidConstants.CLASS_ACTIVITY,
+ checkClass(activityName, AndroidConstants.CLASS_ACTIVITY,
true /* testVisibility */);
}
} else {
// no activity found! Aapt will output an error,
// so we don't have to do anything
- mCurrentActivity = activityName;
+ mCurrentActivity = null;
}
String processName = getAttributeValue(attributes, ATTRIBUTE_PROCESS,
@@ -570,8 +627,8 @@ public class AndroidManifestParser {
private static SAXParserFactory sParserFactory;
private final String mJavaPackage;
- private final String[] mActivities;
- private final String mLauncherActivity;
+ private final Activity[] mActivities;
+ private final Activity mLauncherActivity;
private final String[] mProcesses;
private final Boolean mDebuggable;
private final int mApiLevelRequirement;
@@ -811,18 +868,18 @@ public class AndroidManifestParser {
/**
* Returns the list of activities found in the manifest.
- * @return An array of fully qualified class names, or empty if no activity were found.
+ * @return An array of {@link Activity}, or empty if no activity were found.
*/
- public String[] getActivities() {
+ public Activity[] getActivities() {
return mActivities;
}
/**
* Returns the name of one activity found in the manifest, that is configured to show
* up in the HOME screen.
- * @return the fully qualified name of a HOME activity or null if none were found.
+ * @return The {@link Activity} representing a HOME activity or null if none were found.
*/
- public String getLauncherActivity() {
+ public Activity getLauncherActivity() {
return mLauncherActivity;
}
@@ -880,8 +937,8 @@ public class AndroidManifestParser {
* @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,
+ private AndroidManifestParser(String javaPackage, Activity[] activities,
+ Activity launcherActivity, String[] processes, Boolean debuggable,
int apiLevelRequirement, Instrumentation[] instrumentations, String[] libraries) {
mJavaPackage = javaPackage;
mActivities = activities;