From 61df13dec40be51729ebf96769b3bc6c716e16cc Mon Sep 17 00:00:00 2001 From: Raphael Date: Wed, 10 Jun 2009 11:34:08 -0700 Subject: [PATCH] ADT #1856119: 'android update project' can now update sub-projects. --- .../android/sdkmanager/CommandLineProcessor.java | 30 ++-- .../app/src/com/android/sdkmanager/Main.java | 27 ++++ .../src/com/android/sdkmanager/SdkCommandLine.java | 80 ++++++----- .../sdkmanager/CommandLineProcessorTest.java | 4 +- .../sdklib/internal/project/ProjectCreator.java | 152 +++++++++++---------- 5 files changed, 166 insertions(+), 127 deletions(-) diff --git a/tools/sdkmanager/app/src/com/android/sdkmanager/CommandLineProcessor.java b/tools/sdkmanager/app/src/com/android/sdkmanager/CommandLineProcessor.java index 4a3c16c9..d4da21be 100644 --- a/tools/sdkmanager/app/src/com/android/sdkmanager/CommandLineProcessor.java +++ b/tools/sdkmanager/app/src/com/android/sdkmanager/CommandLineProcessor.java @@ -85,13 +85,13 @@ public class CommandLineProcessor { mLog = logger; mActions = actions; - define(MODE.BOOLEAN, false, GLOBAL_FLAG_VERB, NO_VERB_OBJECT, "v", KEY_VERBOSE, + define(Mode.BOOLEAN, false, GLOBAL_FLAG_VERB, NO_VERB_OBJECT, "v", KEY_VERBOSE, "Verbose mode: errors, warnings and informational messages are printed.", false); - define(MODE.BOOLEAN, false, GLOBAL_FLAG_VERB, NO_VERB_OBJECT, "s", KEY_SILENT, + define(Mode.BOOLEAN, false, GLOBAL_FLAG_VERB, NO_VERB_OBJECT, "s", KEY_SILENT, "Silent mode: only errors are printed out.", false); - define(MODE.BOOLEAN, false, GLOBAL_FLAG_VERB, NO_VERB_OBJECT, "h", KEY_HELP, + define(Mode.BOOLEAN, false, GLOBAL_FLAG_VERB, NO_VERB_OBJECT, "h", KEY_HELP, "This help.", false); } @@ -507,7 +507,7 @@ public class CommandLineProcessor { } } else if (arg.getDefaultValue() != null) { Object v = arg.getDefaultValue(); - if (arg.getMode() != MODE.BOOLEAN || v.equals(Boolean.TRUE)) { + if (arg.getMode() != Mode.BOOLEAN || v.equals(Boolean.TRUE)) { value = v.toString(); } } @@ -537,7 +537,7 @@ public class CommandLineProcessor { * The mode of an argument specifies the type of variable it represents, * whether an extra parameter is required after the flag and how to parse it. */ - static enum MODE { + static enum Mode { /** Argument value is a Boolean. Default value is a Boolean. */ BOOLEAN { @Override @@ -628,7 +628,7 @@ public class CommandLineProcessor { * An argument accepted by the command-line, also called "a flag". * Arguments must have a short version (one letter), a long version name and a description. * They can have a default value, or it can be null. - * Depending on the {@link MODE}, the default value can be a Boolean, an Integer, a String + * Depending on the {@link Mode}, the default value can be a Boolean, an Integer, a String * or a String array (in which case the first item is the current by default.) */ static class Arg { @@ -645,7 +645,7 @@ public class CommandLineProcessor { /** A default value. Can be null. */ private final Object mDefaultValue; /** The argument mode (type + process method). Never null. */ - private final MODE mMode; + private final Mode mMode; /** True if this argument is mandatory for this verb/directobject. */ private final boolean mMandatory; /** Current value. Initially set to the default value. */ @@ -656,15 +656,15 @@ public class CommandLineProcessor { /** * Creates a new argument flag description. * - * @param mode The {@link MODE} for the argument. + * @param mode The {@link Mode} for the argument. * @param mandatory True if this argument is mandatory for this action. * @param directObject The action name. Can be #NO_VERB_OBJECT or #INTERNAL_FLAG. * @param shortName The one-letter short argument name. Cannot be empty nor null. * @param longName The long argument name. Cannot be empty nor null. * @param description The description. Cannot be null. - * @param defaultValue The default value (or values), which depends on the selected {@link MODE}. + * @param defaultValue The default value (or values), which depends on the selected {@link Mode}. */ - public Arg(MODE mode, + public Arg(Mode mode, boolean mandatory, String verb, String directObject, @@ -734,7 +734,7 @@ public class CommandLineProcessor { } /** Returns the argument mode (type + process method). Never null. */ - public MODE getMode() { + public Mode getMode() { return mMode; } @@ -752,21 +752,21 @@ public class CommandLineProcessor { /** * Internal helper to define a new argument for a give action. * - * @param mode The {@link MODE} for the argument. + * @param mode The {@link Mode} for the argument. * @param verb The verb name. Can be #INTERNAL_VERB. * @param directObject The action name. Can be #NO_VERB_OBJECT or #INTERNAL_FLAG. * @param shortName The one-letter short argument name. Cannot be empty nor null. * @param longName The long argument name. Cannot be empty nor null. * @param description The description. Cannot be null. - * @param defaultValue The default value (or values), which depends on the selected {@link MODE}. + * @param defaultValue The default value (or values), which depends on the selected {@link Mode}. */ - protected void define(MODE mode, + protected void define(Mode mode, boolean mandatory, String verb, String directObject, String shortName, String longName, String description, Object defaultValue) { - assert(mandatory || mode == MODE.BOOLEAN); // a boolean mode cannot be mandatory + assert(mandatory || mode == Mode.BOOLEAN); // a boolean mode cannot be mandatory if (directObject == null) { directObject = NO_VERB_OBJECT; diff --git a/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java b/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java index 1836d330..b5988ffc 100644 --- a/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java +++ b/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java @@ -337,6 +337,33 @@ class Main { creator.updateProject(projectDir, target, mSdkCommandLine.getParamName()); + + boolean doSubProjects = mSdkCommandLine.getParamSubProject(); + boolean couldHaveDone = false; + + // If there are any sub-folders with a manifest, try to update them as projects + // too. This will take care of updating any underlying test project even if the + // user changed the folder name. + File[] files = new File(projectDir).listFiles(); + if (files != null) { + for (File dir : files) { + if (dir.isDirectory() && + new File(dir, SdkConstants.FN_ANDROID_MANIFEST_XML).isFile()) { + if (doSubProjects) { + creator.updateProject(dir.getPath(), + target, + mSdkCommandLine.getParamName()); + } else { + couldHaveDone = true; + } + } + } + } + + if (couldHaveDone) { + mSdkLog.printf("It seems that there are sub-projects. If you want to update them\nplease use the --%1$s parameter.", + SdkCommandLine.KEY_SUBPROJECTS); + } } /** diff --git a/tools/sdkmanager/app/src/com/android/sdkmanager/SdkCommandLine.java b/tools/sdkmanager/app/src/com/android/sdkmanager/SdkCommandLine.java index 2ff0c532..c48a3860 100644 --- a/tools/sdkmanager/app/src/com/android/sdkmanager/SdkCommandLine.java +++ b/tools/sdkmanager/app/src/com/android/sdkmanager/SdkCommandLine.java @@ -38,20 +38,21 @@ public class SdkCommandLine extends CommandLineProcessor { public static final String OBJECT_PROJECT = "project"; public static final String OBJECT_ADB = "adb"; - public static final String ARG_ALIAS = "alias"; - public static final String ARG_ACTIVITY = "activity"; - - public static final String KEY_ACTIVITY = ARG_ACTIVITY; - public static final String KEY_PACKAGE = "package"; - public static final String KEY_MODE = "mode"; - public static final String KEY_TARGET_ID = OBJECT_TARGET; - public static final String KEY_NAME = "name"; - public static final String KEY_PATH = "path"; - public static final String KEY_FILTER = "filter"; - public static final String KEY_SKIN = "skin"; - public static final String KEY_SDCARD = "sdcard"; - public static final String KEY_FORCE = "force"; - public static final String KEY_RENAME = "rename"; + public static final String ARG_ALIAS = "alias"; + public static final String ARG_ACTIVITY = "activity"; + + public static final String KEY_ACTIVITY = ARG_ACTIVITY; + public static final String KEY_PACKAGE = "package"; + public static final String KEY_MODE = "mode"; + public static final String KEY_TARGET_ID = OBJECT_TARGET; + public static final String KEY_NAME = "name"; + public static final String KEY_PATH = "path"; + public static final String KEY_FILTER = "filter"; + public static final String KEY_SKIN = "skin"; + public static final String KEY_SDCARD = "sdcard"; + public static final String KEY_FORCE = "force"; + public static final String KEY_RENAME = "rename"; + public static final String KEY_SUBPROJECTS = "subprojects"; /** * Action definitions for SdkManager command line. @@ -97,46 +98,46 @@ public class SdkCommandLine extends CommandLineProcessor { // --- create avd --- - define(MODE.STRING, false, + define(Mode.STRING, false, VERB_CREATE, OBJECT_AVD, "p", KEY_PATH, "Location path of the directory where the new AVD will be created", null); - define(MODE.STRING, true, + define(Mode.STRING, true, VERB_CREATE, OBJECT_AVD, "n", KEY_NAME, "Name of the new AVD", null); - define(MODE.INTEGER, true, + define(Mode.INTEGER, true, VERB_CREATE, OBJECT_AVD, "t", KEY_TARGET_ID, "Target id of the new AVD", null); - define(MODE.STRING, false, + define(Mode.STRING, false, VERB_CREATE, OBJECT_AVD, "s", KEY_SKIN, "Skin of the new AVD", null); - define(MODE.STRING, false, + define(Mode.STRING, false, VERB_CREATE, OBJECT_AVD, "c", KEY_SDCARD, "Path to a shared SD card image, or size of a new sdcard for the new AVD", null); - define(MODE.BOOLEAN, false, + define(Mode.BOOLEAN, false, VERB_CREATE, OBJECT_AVD, "f", KEY_FORCE, "Force creation (override an existing AVD)", false); // --- delete avd --- - define(MODE.STRING, true, + define(Mode.STRING, true, VERB_DELETE, OBJECT_AVD, "n", KEY_NAME, "Name of the AVD to delete", null); // --- move avd --- - define(MODE.STRING, true, + define(Mode.STRING, true, VERB_MOVE, OBJECT_AVD, "n", KEY_NAME, "Name of the AVD to move or rename", null); - define(MODE.STRING, false, + define(Mode.STRING, false, VERB_MOVE, OBJECT_AVD, "r", KEY_RENAME, "New name of the AVD to rename", null); - define(MODE.STRING, false, + define(Mode.STRING, false, VERB_MOVE, OBJECT_AVD, "p", KEY_PATH, "New location path of the directory where to move the AVD", null); // --- update avd --- - define(MODE.STRING, true, + define(Mode.STRING, true, VERB_UPDATE, OBJECT_AVD, "n", KEY_NAME, "Name of the AVD to update", null); @@ -145,41 +146,45 @@ public class SdkCommandLine extends CommandLineProcessor { /* Disabled for ADT 0.9 / Cupcake SDK 1.5_r1 release. [bug #1795718]. This currently does not work, the alias build rules need to be fixed. - define(MODE.ENUM, true, + define(Mode.ENUM, true, VERB_CREATE, OBJECT_PROJECT, "m", KEY_MODE, "Project mode", new String[] { ARG_ACTIVITY, ARG_ALIAS }); */ - define(MODE.STRING, true, + define(Mode.STRING, true, VERB_CREATE, OBJECT_PROJECT, "p", KEY_PATH, "Location path of new project", null); - define(MODE.INTEGER, true, + define(Mode.INTEGER, true, VERB_CREATE, OBJECT_PROJECT, "t", KEY_TARGET_ID, "Target id of the new project", null); - define(MODE.STRING, true, + define(Mode.STRING, true, VERB_CREATE, OBJECT_PROJECT, "k", KEY_PACKAGE, "Package name", null); - define(MODE.STRING, true, + define(Mode.STRING, true, VERB_CREATE, OBJECT_PROJECT, "a", KEY_ACTIVITY, "Activity name", null); - define(MODE.STRING, false, + define(Mode.STRING, false, VERB_CREATE, OBJECT_PROJECT, "n", KEY_NAME, "Project name", null); // --- update project --- - define(MODE.STRING, true, + define(Mode.STRING, true, VERB_UPDATE, OBJECT_PROJECT, "p", KEY_PATH, "Location path of the project", null); - define(MODE.INTEGER, true, + define(Mode.INTEGER, true, VERB_UPDATE, OBJECT_PROJECT, "t", KEY_TARGET_ID, "Target id to set for the project", -1); - define(MODE.STRING, false, + define(Mode.STRING, false, VERB_UPDATE, OBJECT_PROJECT, "n", KEY_NAME, "Project name", null); + define(Mode.BOOLEAN, false, + VERB_UPDATE, OBJECT_PROJECT, + "s", KEY_SUBPROJECTS, + "Also update any projects in sub-folders, such as test projects.", false); } @Override @@ -234,8 +239,13 @@ public class SdkCommandLine extends CommandLineProcessor { return ((String) getValue(null, OBJECT_PROJECT, KEY_PACKAGE)); } - /** Helper to retrieve the --activity for the new project action. */ + /** Helper to retrieve the --activity for any project action. */ public String getParamProjectActivity() { return ((String) getValue(null, OBJECT_PROJECT, KEY_ACTIVITY)); } + + /** Helper to retrieve the --subprojects for any project action. */ + public boolean getParamSubProject() { + return ((Boolean) getValue(null, OBJECT_PROJECT, KEY_SUBPROJECTS)).booleanValue(); + } } diff --git a/tools/sdkmanager/app/tests/com/android/sdkmanager/CommandLineProcessorTest.java b/tools/sdkmanager/app/tests/com/android/sdkmanager/CommandLineProcessorTest.java index 918591b5..a213652d 100644 --- a/tools/sdkmanager/app/tests/com/android/sdkmanager/CommandLineProcessorTest.java +++ b/tools/sdkmanager/app/tests/com/android/sdkmanager/CommandLineProcessorTest.java @@ -41,9 +41,9 @@ public class CommandLineProcessorTest extends TestCase { { "verb1", "action1", "Some action" }, { "verb1", "action2", "Another action" }, }); - define(MODE.STRING, false /*mandatory*/, + define(Mode.STRING, false /*mandatory*/, "verb1", "action1", "1", "first", "non-mandatory flag", null); - define(MODE.STRING, true /*mandatory*/, + define(Mode.STRING, true /*mandatory*/, "verb1", "action1", "2", "second", "mandatory flag", null); } diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectCreator.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectCreator.java index a33eaaa1..29dac833 100644 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectCreator.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/project/ProjectCreator.java @@ -50,7 +50,7 @@ import javax.xml.xpath.XPathFactory; * @hide */ public class ProjectCreator { - + /** Package path substitution string used in template files, i.e. "PACKAGE_PATH" */ private final static String PH_JAVA_FOLDER = "PACKAGE_PATH"; /** Package name substitution string used in template files, i.e. "PACKAGE" */ @@ -59,9 +59,9 @@ public class ProjectCreator { private final static String PH_ACTIVITY_NAME = "ACTIVITY_NAME"; /** Project name substitution string used in template files, i.e. "PROJECT_NAME". */ private final static String PH_PROJECT_NAME = "PROJECT_NAME"; - + private final static String FOLDER_TESTS = "tests"; - + /** Pattern for characters accepted in a project name. Since this will be used as a * directory name, we're being a bit conservative on purpose: dot and space cannot be used. */ public static final Pattern RE_PROJECT_NAME = Pattern.compile("[a-zA-Z0-9_]+"); @@ -69,7 +69,7 @@ public class ProjectCreator { public final static String CHARS_PROJECT_NAME = "a-z A-Z 0-9 _"; /** Pattern for characters accepted in a package name. A package is list of Java identifier - * separated by a dot. We need to have at least one dot (e.g. a two-level package name). + * separated by a dot. We need to have at least one dot (e.g. a two-level package name). * A Java identifier cannot start by a digit. */ public static final Pattern RE_PACKAGE_NAME = Pattern.compile("[a-zA-Z_][a-zA-Z0-9_]*(?:\\.[a-zA-Z_][a-zA-Z0-9_]*)+"); @@ -82,7 +82,7 @@ public class ProjectCreator { /** List of valid characters for a project name. Used for display purposes. */ public final static String CHARS_ACTIVITY_NAME = "a-z A-Z 0-9 _"; - + public enum OutputLevel { /** Silent mode. Project creation will only display errors. */ SILENT, @@ -100,11 +100,11 @@ public class ProjectCreator { private static class ProjectCreateException extends Exception { /** default UID. This will not be serialized anyway. */ private static final long serialVersionUID = 1L; - + ProjectCreateException(String message) { super(message); } - + ProjectCreateException(Throwable t, String format, Object... args) { super(format != null ? String.format(format, args) : format, t); } @@ -113,23 +113,23 @@ public class ProjectCreator { super(String.format(format, args)); } } - + private final OutputLevel mLevel; private final ISdkLog mLog; private final String mSdkFolder; - + public ProjectCreator(String sdkFolder, OutputLevel level, ISdkLog log) { mSdkFolder = sdkFolder; mLevel = level; mLog = log; } - + /** * Creates a new project. *

* The caller should have already checked and sanitized the parameters. - * + * * @param folderPath the folder of the project to create. * @param projectName the name of the project. The name must match the * {@link #RE_PROJECT_NAME} regex. @@ -137,14 +137,16 @@ public class ProjectCreator { * {@link #RE_PACKAGE_NAME} regex. * @param activityName the activity of the project as it will appear in the manifest. Can be * null if no activity should be created. The name must match the - * {@link #RE_ACTIVITY_NAME} regex. + * {@link #RE_ACTIVITY_NAME} regex. * @param target the project target. - * @param isTestProject whether the project to create is a test project. + * @param isTestProject whether the project to create is a test project. Caller should + * initially call this will false. The method will call itself back to create + * a test project as needed. */ public void createProject(String folderPath, String projectName, String packageName, String activityName, IAndroidTarget target, boolean isTestProject) { - + // create project folder if it does not exist File projectFolder = new File(folderPath); if (!projectFolder.exists()) { @@ -156,7 +158,7 @@ public class ProjectCreator { } catch (Exception e) { t = e; } - + if (created) { println("Created project directory: %1$s", projectFolder); } else { @@ -176,7 +178,7 @@ public class ProjectCreator { } catch (Exception e1) { e = e1; } - + if (e != null || error != null) { mLog.error(e, error, projectFolder, SdkConstants.androidCmdName()); } @@ -196,7 +198,7 @@ public class ProjectCreator { PropertyType.DEFAULT); defaultProperties.setAndroidTarget(target); defaultProperties.save(); - + // create an empty build.properties ProjectProperties buildProperties = ProjectProperties.create(folderPath, PropertyType.BUILD); @@ -225,16 +227,16 @@ public class ProjectCreator { keywords.put(PH_PROJECT_NAME, projectName); } else { if (activityName != null) { - // Use the activity as project name + // Use the activity as project name keywords.put(PH_PROJECT_NAME, activityName); } else { // We need a project name. Just pick up the basename of the project // directory. projectName = projectFolder.getName(); - keywords.put(PH_PROJECT_NAME, projectName); + keywords.put(PH_PROJECT_NAME, projectName); } } - + // create the source folder and the java package folders. String srcFolderPath = SdkConstants.FD_SOURCES + File.separator + packagePath; File sourceFolder = createDirs(projectFolder, srcFolderPath); @@ -270,13 +272,13 @@ public class ProjectCreator { /* Make AndroidManifest.xml and build.xml files */ String manifestTemplate = "AndroidManifest.template"; if (isTestProject) { - manifestTemplate = "AndroidManifest.tests.template"; + manifestTemplate = "AndroidManifest.tests.template"; } installTemplate(manifestTemplate, new File(projectFolder, SdkConstants.FN_ANDROID_MANIFEST_XML), keywords, target); - + installTemplate("build.template", new File(projectFolder, SdkConstants.FN_BUILD_XML), keywords); @@ -286,7 +288,7 @@ public class ProjectCreator { // create the test project folder. createDirs(projectFolder, FOLDER_TESTS); File testProjectFolder = new File(folderPath, FOLDER_TESTS); - + createProject(testProjectFolder.getAbsolutePath(), projectName, packageName, activityName, target, true /*isTestProject*/); } @@ -296,7 +298,7 @@ public class ProjectCreator { mLog.error(e, null); } } - + /** * Updates an existing project. *

@@ -308,12 +310,12 @@ public class ProjectCreator { *

  • Refresh/create "sdk" in local.properties *
  • Build.xml: create if not present or no ) in it * - * + * * @param folderPath the folder of the project to update. This folder must exist. * @param target the project target. Can be null. * @param projectName The project name from --name. Can be null. */ - public void updateProject(String folderPath, IAndroidTarget target, String projectName ) { + public void updateProject(String folderPath, IAndroidTarget target, String projectName) { // project folder must exist and be a directory, since this is an update File projectFolder = new File(folderPath); if (!projectFolder.isDirectory()) { @@ -331,7 +333,7 @@ public class ProjectCreator { folderPath); return; } - + // Check there's a default.properties with a target *or* --target was specified ProjectProperties props = ProjectProperties.load(folderPath, PropertyType.DEFAULT); if (props == null || props.getProperty(ProjectProperties.PROPERTY_TARGET) == null) { @@ -351,7 +353,7 @@ public class ProjectCreator { if (props == null) { props = ProjectProperties.create(folderPath, PropertyType.DEFAULT); } - + // set or replace the target props.setAndroidTarget(target); try { @@ -364,7 +366,7 @@ public class ProjectCreator { return; } } - + // Refresh/create "sdk" in local.properties // because the file may already exists and contain other values (like apk config), // we first try to load it. @@ -372,7 +374,7 @@ public class ProjectCreator { if (props == null) { props = ProjectProperties.create(folderPath, PropertyType.LOCAL); } - + // set or replace the sdk location. props.setProperty(ProjectProperties.PROPERTY_SDK, mSdkFolder); try { @@ -384,7 +386,7 @@ public class ProjectCreator { folderPath); return; } - + // Build.xml: create if not present or no in it File buildXml = new File(projectFolder, SdkConstants.FN_BUILD_XML); boolean needsBuildXml = projectName != null || !buildXml.exists(); @@ -397,7 +399,7 @@ public class ProjectCreator { println("File %1$s is too old and needs to be updated.", SdkConstants.FN_BUILD_XML); } } - + if (needsBuildXml) { // create the map for place-holders of values to replace in the templates final HashMap keywords = new HashMap(); @@ -408,13 +410,13 @@ public class ProjectCreator { } else { extractPackageFromManifest(androidManifest, keywords); if (keywords.containsKey(PH_ACTIVITY_NAME)) { - // Use the activity as project name + // Use the activity as project name keywords.put(PH_PROJECT_NAME, keywords.get(PH_ACTIVITY_NAME)); } else { // We need a project name. Just pick up the basename of the project // directory. projectName = projectFolder.getName(); - keywords.put(PH_PROJECT_NAME, projectName); + keywords.put(PH_PROJECT_NAME, projectName); } } @@ -423,7 +425,7 @@ public class ProjectCreator { SdkConstants.FN_BUILD_XML, keywords.get(PH_PROJECT_NAME)); } - + try { installTemplate("build.template", new File(projectFolder, SdkConstants.FN_BUILD_XML), @@ -443,18 +445,18 @@ public class ProjectCreator { try { BufferedReader in = new BufferedReader(new FileReader(file)); String line; - + while ((line = in.readLine()) != null) { if (p.matcher(line).find()) { return true; } } - + in.close(); } catch (Exception e) { // ignore } - + return false; } @@ -464,8 +466,8 @@ public class ProjectCreator { * The keywords dictionary is always filed the package name under the key {@link #PH_PACKAGE}. * If an activity name can be found, it is filed under the key {@link #PH_ACTIVITY_NAME}. * When no activity is found, this key is not created. - * - * @param manifestFile The AndroidManifest.xml file + * + * @param manifestFile The AndroidManifest.xml file * @param outKeywords Place where to put the out parameters: package and activity names. * @return True if the package/activity was parsed and updated in the keyword dictionary. */ @@ -474,9 +476,9 @@ public class ProjectCreator { try { final String nsPrefix = "android"; final String nsURI = SdkConstants.NS_RESOURCES; - + XPath xpath = XPathFactory.newInstance().newXPath(); - + xpath.setNamespaceContext(new NamespaceContext() { public String getNamespaceURI(String prefix) { if (nsPrefix.equals(prefix)) { @@ -501,18 +503,18 @@ public class ProjectCreator { } return null; } - + }); - + InputSource source = new InputSource(new FileReader(manifestFile)); String packageName = xpath.evaluate("/manifest/@package", source); - source = new InputSource(new FileReader(manifestFile)); - + source = new InputSource(new FileReader(manifestFile)); + // Select the "android:name" attribute of all nodes but only if they // contain a sub-node with an "android:name" attribute which // is 'android.intent.action.MAIN' and an with an - // "android:name" attribute which is 'android.intent.category.LAUNCHER' + // "android:name" attribute which is 'android.intent.category.LAUNCHER' String expression = String.format("/manifest/application/activity" + "[intent-filter/action/@%1$s:name='android.intent.action.MAIN' and " + "intent-filter/category/@%1$s:name='android.intent.category.LAUNCHER']" + @@ -524,7 +526,7 @@ public class ProjectCreator { // If we get here, both XPath expressions were valid so we're most likely dealing // with an actual AndroidManifest.xml file. The nodes may not have the requested // attributes though, if which case we should warn. - + if (packageName == null || packageName.length() == 0) { mLog.error(null, "Missing in '%1$s'", @@ -545,14 +547,14 @@ public class ProjectCreator { "Only the first one will be used. If this is not appropriate, you need\n" + "to specify one of these values manually instead:", manifestFile.getName()); - + for (int i = 0; i < activityNames.getLength(); i++) { String name = activityNames.item(i).getNodeValue(); name = combinePackageActivityNames(packageName, name); println("- %1$s", name); } } - + if (activityName.length() == 0) { mLog.warning("Missing in '%2$s'.\n" + "No activity will be generated.", @@ -563,7 +565,7 @@ public class ProjectCreator { outKeywords.put(PH_PACKAGE, packageName); return true; - + } catch (IOException e) { mLog.error(e, "Failed to read %1$s", manifestFile.getName()); } catch (XPathExpressionException e) { @@ -572,10 +574,10 @@ public class ProjectCreator { "Failed to parse %1$s", manifestFile.getName()); } - + return false; } - + private String combinePackageActivityNames(String packageName, String activityName) { // Activity Name can have 3 forms: // - ".Name" means this is a class name in the given package name. @@ -585,7 +587,7 @@ public class ProjectCreator { // To be valid, the package name should have at least two components. This is checked // later during the creation of the build.xml file, so we just need to detect there's // a dot but not at pos==0. - + int pos = activityName.indexOf('.'); if (pos == 0) { return packageName + activityName; @@ -600,12 +602,12 @@ public class ProjectCreator { * Installs a new file that is based on a template file provided by a given target. * Each match of each key from the place-holder map in the template will be replaced with its * corresponding value in the created file. - * + * * @param templateName the name of to the template file * @param destFile the path to the destination file, relative to the project * @param placeholderMap a map of (place-holder, value) to create the file from the template. * @param target the Target of the project that will be providing the template. - * @throws ProjectCreateException + * @throws ProjectCreateException */ private void installTemplate(String templateName, File destFile, Map placeholderMap, IAndroidTarget target) @@ -621,11 +623,11 @@ public class ProjectCreator { * Installs a new file that is based on a template file provided by the tools folder. * Each match of each key from the place-holder map in the template will be replaced with its * corresponding value in the created file. - * + * * @param templateName the name of to the template file * @param destFile the path to the destination file, relative to the project * @param placeholderMap a map of (place-holder, value) to create the file from the template. - * @throws ProjectCreateException + * @throws ProjectCreateException */ private void installTemplate(String templateName, File destFile, Map placeholderMap) @@ -641,38 +643,38 @@ public class ProjectCreator { * Installs a new file that is based on a template. * Each match of each key from the place-holder map in the template will be replaced with its * corresponding value in the created file. - * + * * @param sourcePath the full path to the source template file * @param destFile the destination file * @param placeholderMap a map of (place-holder, value) to create the file from the template. - * @throws ProjectCreateException + * @throws ProjectCreateException */ private void installFullPathTemplate(String sourcePath, File destFile, Map placeholderMap) throws ProjectCreateException { - + boolean existed = destFile.exists(); - + try { BufferedWriter out = new BufferedWriter(new FileWriter(destFile)); BufferedReader in = new BufferedReader(new FileReader(sourcePath)); String line; - + while ((line = in.readLine()) != null) { for (String key : placeholderMap.keySet()) { line = line.replace(key, placeholderMap.get(key)); } - + out.write(line); out.newLine(); } - + out.close(); in.close(); } catch (Exception e) { throw new ProjectCreateException(e, "Could not access %1$s: %2$s", destFile, e.getMessage()); } - + println("%1$s file %2$s", existed ? "Updated" : "Added", destFile); @@ -683,7 +685,7 @@ public class ProjectCreator { *

    * This is just a convenience wrapper around {@link ISdkLog#printf(String, Object...)} from * {@link #mLog} after testing if ouput level is {@link OutputLevel#VERBOSE}. - * + * * @param format Format for String.format * @param args Arguments for String.format */ @@ -698,10 +700,10 @@ public class ProjectCreator { /** * Creates a new folder, along with any parent folders that do not exists. - * + * * @param parent the parent folder * @param name the name of the directory to create. - * @throws ProjectCreateException + * @throws ProjectCreateException */ private File createDirs(File parent, String name) throws ProjectCreateException { final File newFolder = new File(parent, name); @@ -730,7 +732,7 @@ public class ProjectCreator { "Could not determine canonical path of created directory", e); } } - + return newFolder; } @@ -738,7 +740,7 @@ public class ProjectCreator { * Strips the string of beginning and trailing characters (multiple * characters will be stripped, example stripString("..test...", '.') * results in "test"; - * + * * @param s the string to strip * @param strip the character to strip from beginning and end * @return the stripped string or the empty string if everything is stripped. @@ -746,24 +748,24 @@ public class ProjectCreator { private static String stripString(String s, char strip) { final int sLen = s.length(); int newStart = 0, newEnd = sLen - 1; - + while (newStart < sLen && s.charAt(newStart) == strip) { newStart++; } while (newEnd >= 0 && s.charAt(newEnd) == strip) { newEnd--; } - + /* * newEnd contains a char we want, and substring takes end as being * exclusive */ newEnd++; - + if (newStart >= sLen || newEnd < 0) { return ""; } - + return s.substring(newStart, newEnd); } } -- 2.11.0