AI 144419: am: CL 144382 am: CL 144366 Activity Launcher filters out unlauncheable activity (bug #1736754)

Activities that do not have an action, or that are set to not be exported cannot be launched from 'am start...' so they should not be considered when finding an activity to launch.
  Original author: xav
  Merged from: //branches/cupcake/...
  Original author: android-build

Automated import of CL 144419
This commit is contained in:
Xavier Ducrohet
2009-04-02 23:52:36 -07:00
committed by The Android Open Source Project
parent 8dc883fe46
commit 17915d4e6d
5 changed files with 144 additions and 69 deletions

View File

@@ -1078,7 +1078,7 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener
/** /**
* Performs the installation of an application whose package has been uploaded on the device. * Performs the installation of an application whose package has been uploaded on the device.
* <p/>Before doing it, if the application is already running on the device, it is killed. *
* @param launchInfo the {@link DelayedLaunchInfo}. * @param launchInfo the {@link DelayedLaunchInfo}.
* @param remotePath the path of the application package in the device tmp folder. * @param remotePath the path of the application package in the device tmp folder.
* @param device the device on which to install the application. * @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, private String doInstall(DelayedLaunchInfo launchInfo, final String remotePath,
final IDevice device, boolean reinstall) throws IOException { 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(); InstallReceiver receiver = new InstallReceiver();
try { try {
String cmd = String.format( String cmd = String.format(

View File

@@ -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.AndroidConstants;
import com.android.ide.eclipse.common.project.AndroidManifestParser; import com.android.ide.eclipse.common.project.AndroidManifestParser;
import com.android.ide.eclipse.common.project.BaseProjectHelper; 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.IFile;
import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProject;
@@ -247,7 +248,7 @@ public class LaunchConfigDelegate extends LaunchConfigurationDelegate {
activityName = getActivityName(configuration); activityName = getActivityName(configuration);
// Get the full activity list and make sure the one we got matches. // 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. // first we check that there are, in fact, activities.
if (activities.length == 0) { if (activities.length == 0) {
@@ -261,7 +262,10 @@ public class LaunchConfigDelegate extends LaunchConfigurationDelegate {
// if the activity we got is null, we look for the default one. // if the activity we got is null, we look for the default one.
AdtPlugin.printErrorToConsole(project, AdtPlugin.printErrorToConsole(project,
"No activity specified! Getting the launcher activity."); "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 there's no default activity. We revert to a sync-only launch.
if (activityName == null) { if (activityName == null) {
@@ -271,8 +275,8 @@ public class LaunchConfigDelegate extends LaunchConfigurationDelegate {
// check the one we got from the config matches any from the list // check the one we got from the config matches any from the list
boolean match = false; boolean match = false;
for (String a : activities) { for (Activity a : activities) {
if (a != null && a.equals(activityName)) { if (a != null && a.getName().equals(activityName)) {
match = true; match = true;
break; break;
} }
@@ -282,7 +286,10 @@ public class LaunchConfigDelegate extends LaunchConfigurationDelegate {
if (match == false) { if (match == false) {
AdtPlugin.printErrorToConsole(project, AdtPlugin.printErrorToConsole(project,
"The specified activity does not exist! Getting the launcher activity."); "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 there's no default activity. We revert to a sync-only launch.
if (activityName == null) { if (activityName == null) {
@@ -291,7 +298,10 @@ public class LaunchConfigDelegate extends LaunchConfigurationDelegate {
} }
} }
} else if (config.mLaunchAction == ACTION_DEFAULT) { } 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 there's no default activity. We revert to a sync-only launch.
if (activityName == null) { if (activityName == null) {

View File

@@ -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.AndroidManifestParser;
import com.android.ide.eclipse.common.project.BaseProjectHelper; import com.android.ide.eclipse.common.project.BaseProjectHelper;
import com.android.ide.eclipse.common.project.ProjectChooserHelper; 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.IProject;
import org.eclipse.core.resources.IResource; 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.Group;
import org.eclipse.swt.widgets.Text; import org.eclipse.swt.widgets.Text;
import java.util.ArrayList;
/** /**
* Class for the main launch configuration tab. * Class for the main launch configuration tab.
*/ */
@@ -66,7 +69,7 @@ public class MainLaunchConfigTab extends AbstractLaunchConfigurationTab {
private Button mProjButton; private Button mProjButton;
private Combo mActivityCombo; private Combo mActivityCombo;
private String[] mActivities; private final ArrayList<Activity> mActivities = new ArrayList<Activity>();
private WidgetListener mListener = new WidgetListener(); private WidgetListener mListener = new WidgetListener();
@@ -214,8 +217,9 @@ public class MainLaunchConfigTab extends AbstractLaunchConfigurationTab {
// add the activity // add the activity
int selection = mActivityCombo.getSelectionIndex(); int selection = mActivityCombo.getSelectionIndex();
if (mActivities != null && selection >=0 && selection < mActivities.length) { if (mActivities != null && selection >=0 && selection < mActivities.size()) {
configuration.setAttribute(LaunchConfigDelegate.ATTR_ACTIVITY, mActivities[selection]); configuration.setAttribute(LaunchConfigDelegate.ATTR_ACTIVITY,
mActivities.get(selection).getName());
} }
// link the project and the launch config. // link the project and the launch config.
@@ -349,11 +353,11 @@ public class MainLaunchConfigTab extends AbstractLaunchConfigurationTab {
mActivityCombo.setEnabled(true); mActivityCombo.setEnabled(true);
if (activityName == null || activityName.equals(EMPTY_STRING)) { if (activityName == null || activityName.equals(EMPTY_STRING)) {
mActivityCombo.clearSelection(); 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. // look for the name of the activity in the combo.
boolean found = false; boolean found = false;
for (int i = 0 ; i < mActivities.length ; i++) { for (int i = 0 ; i < mActivities.size() ; i++) {
if (activityName.equals(mActivities[i])) { if (activityName.equals(mActivities.get(i).getName())) {
found = true; found = true;
mActivityCombo.select(i); mActivityCombo.select(i);
break; break;
@@ -404,17 +408,22 @@ public class MainLaunchConfigTab extends AbstractLaunchConfigurationTab {
BaseProjectHelper.getJavaProject(project), null /* errorListener */, BaseProjectHelper.getJavaProject(project), null /* errorListener */,
true /* gatherData */, false /* markErrors */); true /* gatherData */, false /* markErrors */);
if (manifestParser != null) { if (manifestParser != null) {
mActivities = manifestParser.getActivities(); Activity[] activities = manifestParser.getActivities();
mActivities.clear();
mActivityCombo.removeAll(); 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) { if (mLaunchAction == LaunchConfigDelegate.ACTION_ACTIVITY) {
mActivityCombo.setEnabled(true); mActivityCombo.setEnabled(true);
} }
for (String s : mActivities) {
mActivityCombo.add(s);
}
} else { } else {
mActivityCombo.setEnabled(false); 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 // 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. // the parsing. In either case, we empty the activity list.
mActivityCombo.removeAll(); mActivityCombo.removeAll();
mActivities = null; mActivities.clear();
} }
/** /**

View File

@@ -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.adt.sdk.Sdk.ITargetChangeListener;
import com.android.ide.eclipse.common.AndroidConstants; import com.android.ide.eclipse.common.AndroidConstants;
import com.android.ide.eclipse.common.project.AndroidManifestParser; 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.IAndroidTarget;
import com.android.sdklib.SdkConstants; import com.android.sdklib.SdkConstants;
import com.android.sdklib.project.ProjectProperties; import com.android.sdklib.project.ProjectProperties;
@@ -859,6 +860,7 @@ public class NewProjectCreationPage extends WizardPage {
} }
String packageName = null; String packageName = null;
Activity activity = null;
String activityName = null; String activityName = null;
int minSdkVersion = AndroidManifestParser.INVALID_MIN_SDK; int minSdkVersion = AndroidManifestParser.INVALID_MIN_SDK;
try { try {
@@ -866,11 +868,11 @@ public class NewProjectCreationPage extends WizardPage {
minSdkVersion = manifestData.getApiLevelRequirement(); minSdkVersion = manifestData.getApiLevelRequirement();
// try to get the first launcher activity. If none, just take the first activity. // try to get the first launcher activity. If none, just take the first activity.
activityName = manifestData.getLauncherActivity(); activity = manifestData.getLauncherActivity();
if (activityName == null) { if (activity == null) {
String[] activities = manifestData.getActivities(); Activity[] activities = manifestData.getActivities();
if (activities != null && activities.length > 0) { if (activities != null && activities.length > 0) {
activityName = activities[0]; activity = activities[0];
} }
} }
} catch (Exception e) { } catch (Exception e) {
@@ -881,7 +883,10 @@ public class NewProjectCreationPage extends WizardPage {
mPackageNameField.setText(packageName); mPackageNameField.setText(packageName);
} }
activityName = AndroidManifestParser.extractActivityName(activityName, packageName); if (activity != null) {
activityName = AndroidManifestParser.extractActivityName(activity.getName(),
packageName);
}
if (activityName != null && activityName.length() > 0) { if (activityName != null && activityName.length() > 0) {
mInternalActivityNameUpdate = true; mInternalActivityNameUpdate = true;
@@ -1136,7 +1141,7 @@ public class NewProjectCreationPage extends WizardPage {
MSG_ERROR); MSG_ERROR);
} }
String[] activities = manifestData.getActivities(); Activity[] activities = manifestData.getActivities();
if (activities == null || activities.length == 0) { if (activities == null || activities.length == 0) {
// This is acceptable now as long as no activity needs to be created // This is acceptable now as long as no activity needs to be created
if (isCreateActivity()) { if (isCreateActivity()) {

View File

@@ -53,6 +53,7 @@ public class AndroidManifestParser {
private final static String ATTRIBUTE_DEBUGGABLE = "debuggable"; //$NON-NLS-$ 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_MIN_SDK_VERSION = "minSdkVersion"; //$NON-NLS-$
private final static String ATTRIBUTE_TARGET_PACKAGE = "targetPackage"; //$NON-NLS-1$ 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_MANIFEST = "manifest"; //$NON-NLS-1$
private final static String NODE_APPLICATION = "application"; //$NON-NLS-1$ private final static String NODE_APPLICATION = "application"; //$NON-NLS-1$
private final static String NODE_ACTIVITY = "activity"; //$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 mName;
private final String mTargetPackage; private final String mTargetPackage;
public Instrumentation(String name, String targetPackage) { Instrumentation(String name, String targetPackage) {
mName = name; mName = name;
mTargetPackage = targetPackage; 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. * XML error & data handler used when parsing the AndroidManifest.xml file.
* <p/> * <p/>
@@ -117,9 +172,9 @@ public class AndroidManifestParser {
/** Application package */ /** Application package */
private String mPackage; private String mPackage;
/** List of all activities */ /** List of all activities */
private final ArrayList<String> mActivities = new ArrayList<String>(); private final ArrayList<Activity> mActivities = new ArrayList<Activity>();
/** Launcher activity */ /** Launcher activity */
private String mLauncherActivity = null; private Activity mLauncherActivity = null;
/** list of process names declared by the manifest */ /** list of process names declared by the manifest */
private Set<String> mProcesses = null; private Set<String> mProcesses = null;
/** debuggable attribute value. If null, the attribute is not present. */ /** debuggable attribute value. If null, the attribute is not present. */
@@ -139,9 +194,7 @@ public class AndroidManifestParser {
private boolean mMarkErrors = false; private boolean mMarkErrors = false;
private int mCurrentLevel = 0; private int mCurrentLevel = 0;
private int mValidLevel = 0; private int mValidLevel = 0;
private boolean mFoundMainAction = false; private Activity mCurrentActivity = null;
private boolean mFoundLauncherCategory = false;
private String mCurrentActivity = null;
private Locator mLocator; private Locator mLocator;
/** /**
@@ -173,8 +226,8 @@ public class AndroidManifestParser {
* Returns the list of activities found in the manifest. * 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 fully qualified class names, or empty if no activity were found.
*/ */
String[] getActivities() { Activity[] getActivities() {
return mActivities.toArray(new String[mActivities.size()]); return mActivities.toArray(new Activity[mActivities.size()]);
} }
/** /**
@@ -182,7 +235,7 @@ public class AndroidManifestParser {
* up in the HOME screen. * up in the HOME screen.
* @return the fully qualified name of a HOME activity or null if none were found. * @return the fully qualified name of a HOME activity or null if none were found.
*/ */
String getLauncherActivity() { Activity getLauncherActivity() {
return mLauncherActivity; return mLauncherActivity;
} }
@@ -314,27 +367,26 @@ public class AndroidManifestParser {
case LEVEL_INTENT_FILTER: case LEVEL_INTENT_FILTER:
// only process this level if we are in an activity // only process this level if we are in an activity
if (mCurrentActivity != null && NODE_INTENT.equals(localName)) { if (mCurrentActivity != null && NODE_INTENT.equals(localName)) {
// if we're at the intent level, lets reset some flag to mCurrentActivity.resetIntentFilter();
// be used when parsing the children
mFoundMainAction = false;
mFoundLauncherCategory = false;
mValidLevel++; mValidLevel++;
} }
break; break;
case LEVEL_CATEGORY: case LEVEL_CATEGORY:
if (mCurrentActivity != null && mLauncherActivity == null) { if (mCurrentActivity != null) {
if (NODE_ACTION.equals(localName)) { if (NODE_ACTION.equals(localName)) {
// get the name attribute // get the name attribute
if (ACTION_MAIN.equals( String action = getAttributeValue(attributes, ATTRIBUTE_NAME,
getAttributeValue(attributes, ATTRIBUTE_NAME, true /* hasNamespace */);
true /* hasNamespace */))) { if (action != null) {
mFoundMainAction = true; mCurrentActivity.setHasAction(true);
mCurrentActivity.setHasMainAction(
ACTION_MAIN.equals(action));
} }
} else if (NODE_CATEGORY.equals(localName)) { } else if (NODE_CATEGORY.equals(localName)) {
if (CATEGORY_LAUNCHER.equals( String category = getAttributeValue(attributes, ATTRIBUTE_NAME,
getAttributeValue(attributes, ATTRIBUTE_NAME, true /* hasNamespace */);
true /* hasNamespace */))) { if (CATEGORY_LAUNCHER.equals(category)) {
mFoundLauncherCategory = true; mCurrentActivity.setHasLauncherCategory(true);
} }
} }
@@ -378,8 +430,7 @@ public class AndroidManifestParser {
case LEVEL_INTENT_FILTER: case LEVEL_INTENT_FILTER:
// if we found both a main action and a launcher category, this is our // if we found both a main action and a launcher category, this is our
// launcher activity! // launcher activity!
if (mCurrentActivity != null && if (mCurrentActivity != null && mCurrentActivity.isHomeActivity()) {
mFoundMainAction && mFoundLauncherCategory) {
mLauncherActivity = mCurrentActivity; mLauncherActivity = mCurrentActivity;
} }
break; break;
@@ -432,17 +483,23 @@ public class AndroidManifestParser {
String activityName = getAttributeValue(attributes, ATTRIBUTE_NAME, String activityName = getAttributeValue(attributes, ATTRIBUTE_NAME,
true /* hasNamespace */); true /* hasNamespace */);
if (activityName != null) { 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); mActivities.add(mCurrentActivity);
if (mMarkErrors) { if (mMarkErrors) {
checkClass(mCurrentActivity, AndroidConstants.CLASS_ACTIVITY, checkClass(activityName, AndroidConstants.CLASS_ACTIVITY,
true /* testVisibility */); true /* testVisibility */);
} }
} else { } else {
// no activity found! Aapt will output an error, // no activity found! Aapt will output an error,
// so we don't have to do anything // so we don't have to do anything
mCurrentActivity = activityName; mCurrentActivity = null;
} }
String processName = getAttributeValue(attributes, ATTRIBUTE_PROCESS, String processName = getAttributeValue(attributes, ATTRIBUTE_PROCESS,
@@ -570,8 +627,8 @@ public class AndroidManifestParser {
private static SAXParserFactory sParserFactory; private static SAXParserFactory sParserFactory;
private final String mJavaPackage; private final String mJavaPackage;
private final String[] mActivities; private final Activity[] mActivities;
private final String mLauncherActivity; private final Activity mLauncherActivity;
private final String[] mProcesses; private final String[] mProcesses;
private final Boolean mDebuggable; private final Boolean mDebuggable;
private final int mApiLevelRequirement; private final int mApiLevelRequirement;
@@ -811,18 +868,18 @@ public class AndroidManifestParser {
/** /**
* Returns the list of activities found in the manifest. * 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; return mActivities;
} }
/** /**
* Returns the name of one activity found in the manifest, that is configured to show * Returns the name of one activity found in the manifest, that is configured to show
* up in the HOME screen. * 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; return mLauncherActivity;
} }
@@ -880,8 +937,8 @@ public class AndroidManifestParser {
* @param instrumentations the list of instrumentations parsed from the manifest. * @param instrumentations the list of instrumentations parsed from the manifest.
* @param libraries the list of libraries in use parsed from the manifest. * @param libraries the list of libraries in use parsed from the manifest.
*/ */
private AndroidManifestParser(String javaPackage, String[] activities, private AndroidManifestParser(String javaPackage, Activity[] activities,
String launcherActivity, String[] processes, Boolean debuggable, Activity launcherActivity, String[] processes, Boolean debuggable,
int apiLevelRequirement, Instrumentation[] instrumentations, String[] libraries) { int apiLevelRequirement, Instrumentation[] instrumentations, String[] libraries) {
mJavaPackage = javaPackage; mJavaPackage = javaPackage;
mActivities = activities; mActivities = activities;