Mainpublic class Main extends Object Main class for the 'android' application. |
Fields Summary |
---|
private static final String | TOOLSDIRJava property that defines the location of the sdk/tools directory. | private static final String | WORKDIRJava property that defines the working directory. On Windows the current working directory
is actually the tools dir, in which case this is used to get the original CWD. | private static final String[] | BOOLEAN_YES_REPLIES | private static final String[] | BOOLEAN_NO_REPLIES | private static final Pattern | RE_AVD_NAMERegex used to validate characters that compose an AVD name. | private static final String | CHARS_AVD_NAMEList of valid characters for an AVD name. Used for display purposes. | private String | mSdkFolderPath to the SDK folder. This is the parent of {@link #TOOLSDIR}. | private com.android.sdklib.ISdkLog | mSdkLogLogger object. Use this to print normal output, warnings or errors. | private com.android.sdklib.SdkManager | mSdkManagerThe SDK manager parses the SDK folder and gives access to the content. | private SdkCommandLine | mSdkCommandLineCommand-line processor with options specific to SdkManager. | private File | mWorkDirThe working directory, either null or set to an existing absolute canonical directory. |
Methods Summary |
---|
private void | createAvd()Creates a new AVD. This is a text based creation with command line prompt.
// find a matching target
int targetId = mSdkCommandLine.getParamTargetId();
IAndroidTarget target = null;
if (targetId >= 1 && targetId <= mSdkManager.getTargets().length) {
target = mSdkManager.getTargets()[targetId-1]; // target it is 1-based
} else {
errorAndExit("Target id is not valid. Use '%s list targets' to get the target ids.",
SdkConstants.androidCmdName());
}
try {
boolean removePrevious = false;
AvdManager avdManager = new AvdManager(mSdkManager, mSdkLog);
String avdName = mSdkCommandLine.getParamName();
if (!RE_AVD_NAME.matcher(avdName).matches()) {
errorAndExit(
"AVD name '%1$s' contains invalid characters.\nAllowed characters are: %2$s",
avdName, CHARS_AVD_NAME);
return;
}
AvdInfo info = avdManager.getAvd(avdName, false /*validAvdOnly*/);
if (info != null) {
if (mSdkCommandLine.getFlagForce()) {
removePrevious = true;
mSdkLog.warning(
"Android Virtual Device '%s' already exists and will be replaced.",
avdName);
} else {
errorAndExit("Android Virtual Device '%s' already exists.", avdName);
return;
}
}
String paramFolderPath = mSdkCommandLine.getParamLocationPath();
File avdFolder = null;
if (paramFolderPath != null) {
avdFolder = new File(paramFolderPath);
} else {
avdFolder = new File(AndroidLocation.getFolder() + AndroidLocation.FOLDER_AVD,
avdName + AvdManager.AVD_FOLDER_EXTENSION);
}
Map<String, String> hardwareConfig = null;
if (target.isPlatform()) {
try {
hardwareConfig = promptForHardware(target);
} catch (IOException e) {
errorAndExit(e.getMessage());
}
}
AvdInfo oldAvdInfo = null;
if (removePrevious) {
oldAvdInfo = avdManager.getAvd(avdName, false /*validAvdOnly*/);
}
// Validate skin is either default (empty) or NNNxMMM or a valid skin name.
String skin = mSdkCommandLine.getParamSkin();
if (skin != null && skin.length() == 0) {
skin = null;
}
if (skin != null) {
boolean valid = false;
// Is it a know skin name for this target?
for (String s : target.getSkins()) {
if (skin.equalsIgnoreCase(s)) {
skin = s; // Make skin names case-insensitive.
valid = true;
break;
}
}
// Is it NNNxMMM?
if (!valid) {
valid = AvdManager.NUMERIC_SKIN_SIZE.matcher(skin).matches();
}
if (!valid) {
displaySkinList(target, "Valid skins: ");
errorAndExit("'%s' is not a valid skin name or size (NNNxMMM)", skin);
return;
}
}
AvdInfo newAvdInfo = avdManager.createAvd(avdFolder,
avdName,
target,
skin,
mSdkCommandLine.getParamSdCard(),
hardwareConfig,
removePrevious);
if (newAvdInfo != null &&
oldAvdInfo != null &&
!oldAvdInfo.getPath().equals(newAvdInfo.getPath())) {
mSdkLog.warning("Removing previous AVD directory at %s", oldAvdInfo.getPath());
// Remove the old data directory
File dir = new File(oldAvdInfo.getPath());
avdManager.recursiveDelete(dir);
dir.delete();
// Remove old AVD info from manager
avdManager.removeAvd(oldAvdInfo);
}
} catch (AndroidLocationException e) {
errorAndExit(e.getMessage());
}
| private void | createLogger()Creates the {@link #mSdkLog} object.
This must be done before {@link #init()} as it will be used to report errors.
mSdkLog = new ISdkLog() {
public void error(Throwable t, String errorFormat, Object... args) {
if (errorFormat != null) {
System.err.printf("Error: " + errorFormat, args);
if (!errorFormat.endsWith("\n")) {
System.err.printf("\n");
}
}
if (t != null) {
System.err.printf("Error: %s\n", t.getMessage());
}
}
public void warning(String warningFormat, Object... args) {
if (mSdkCommandLine.isVerbose()) {
System.out.printf("Warning: " + warningFormat, args);
if (!warningFormat.endsWith("\n")) {
System.out.printf("\n");
}
}
}
public void printf(String msgFormat, Object... args) {
System.out.printf(msgFormat, args);
}
};
| private void | createProject()Creates a new Android project based on command-line parameters
// get the target and try to resolve it.
int targetId = mSdkCommandLine.getParamTargetId();
IAndroidTarget[] targets = mSdkManager.getTargets();
if (targetId < 1 || targetId > targets.length) {
errorAndExit("Target id is not valid. Use '%s list targets' to get the target ids.",
SdkConstants.androidCmdName());
}
IAndroidTarget target = targets[targetId - 1];
ProjectCreator creator = new ProjectCreator(mSdkFolder,
mSdkCommandLine.isVerbose() ? OutputLevel.VERBOSE :
mSdkCommandLine.isSilent() ? OutputLevel.SILENT :
OutputLevel.NORMAL,
mSdkLog);
String projectDir = getProjectLocation(mSdkCommandLine.getParamLocationPath());
String projectName = mSdkCommandLine.getParamName();
String packageName = mSdkCommandLine.getParamProjectPackage();
String activityName = mSdkCommandLine.getParamProjectActivity();
if (projectName != null &&
!ProjectCreator.RE_PROJECT_NAME.matcher(projectName).matches()) {
errorAndExit(
"Project name '%1$s' contains invalid characters.\nAllowed characters are: %2$s",
projectName, ProjectCreator.CHARS_PROJECT_NAME);
return;
}
if (activityName != null &&
!ProjectCreator.RE_ACTIVITY_NAME.matcher(activityName).matches()) {
errorAndExit(
"Activity name '%1$s' contains invalid characters.\nAllowed characters are: %2$s",
activityName, ProjectCreator.CHARS_ACTIVITY_NAME);
return;
}
if (packageName != null &&
!ProjectCreator.RE_PACKAGE_NAME.matcher(packageName).matches()) {
errorAndExit(
"Package name '%1$s' contains invalid characters.\n" +
"A package name must be constitued of two Java identifiers.\n" +
"Each identifier allowed characters are: %2$s",
packageName, ProjectCreator.CHARS_PACKAGE_NAME);
return;
}
creator.createProject(projectDir,
projectName,
packageName,
activityName,
target,
false /* isTestProject*/);
| private void | deleteAvd()Delete an AVD. If the AVD name is not part of the available ones look for an
invalid AVD (one not loaded due to some error) to remove it too.
try {
String avdName = mSdkCommandLine.getParamName();
AvdManager avdManager = new AvdManager(mSdkManager, mSdkLog);
AvdInfo info = avdManager.getAvd(avdName, false /*validAvdOnly*/);
if (info == null) {
errorAndExit("There is no Android Virtual Device named '%s'.", avdName);
return;
}
avdManager.deleteAvd(info, mSdkLog);
} catch (AndroidLocationException e) {
errorAndExit(e.getMessage());
}
| private void | displayAvdList()Displays the list of available AVDs.
try {
AvdManager avdManager = new AvdManager(mSdkManager, mSdkLog);
mSdkLog.printf("Available Android Virtual Devices:\n");
AvdInfo[] avds = avdManager.getValidAvds();
for (int index = 0 ; index < avds.length ; index++) {
AvdInfo info = avds[index];
if (index > 0) {
mSdkLog.printf("---------\n");
}
mSdkLog.printf(" Name: %s\n", info.getName());
mSdkLog.printf(" Path: %s\n", info.getPath());
// get the target of the AVD
IAndroidTarget target = info.getTarget();
if (target.isPlatform()) {
mSdkLog.printf(" Target: %s (API level %d)\n", target.getName(),
target.getApiVersionNumber());
} else {
mSdkLog.printf(" Target: %s (%s)\n", target.getName(), target
.getVendor());
mSdkLog.printf(" Based on Android %s (API level %d)\n", target
.getApiVersionName(), target.getApiVersionNumber());
}
// display some extra values.
Map<String, String> properties = info.getProperties();
String skin = properties.get(AvdManager.AVD_INI_SKIN_NAME);
if (skin != null) {
mSdkLog.printf(" Skin: %s\n", skin);
}
String sdcard = properties.get(AvdManager.AVD_INI_SDCARD_SIZE);
if (sdcard == null) {
sdcard = properties.get(AvdManager.AVD_INI_SDCARD_PATH);
}
if (sdcard != null) {
mSdkLog.printf(" Sdcard: %s\n", sdcard);
}
}
// Are there some unused AVDs?
AvdInfo[] badAvds = avdManager.getBrokenAvds();
if (badAvds.length == 0) {
return;
}
mSdkLog.printf("\nThe following Android Virtual Devices could not be loaded:\n");
boolean needSeparator = false;
for (AvdInfo info : badAvds) {
if (needSeparator) {
mSdkLog.printf("---------\n");
}
mSdkLog.printf(" Name: %s\n", info.getName() == null ? "--" : info.getName());
mSdkLog.printf(" Path: %s\n", info.getPath() == null ? "--" : info.getPath());
String error = info.getErrorMessage();
mSdkLog.printf(" Error: %s\n", error == null ? "Uknown error" : error);
needSeparator = true;
}
} catch (AndroidLocationException e) {
errorAndExit(e.getMessage());
}
| private void | displaySkinList(com.android.sdklib.IAndroidTarget target, java.lang.String message)Displays the skins valid for the given target.
String[] skins = target.getSkins();
String defaultSkin = target.getDefaultSkin();
mSdkLog.printf(message);
if (skins != null) {
boolean first = true;
for (String skin : skins) {
if (first == false) {
mSdkLog.printf(", ");
} else {
first = false;
}
mSdkLog.printf(skin);
if (skin.equals(defaultSkin)) {
mSdkLog.printf(" (default)");
}
}
mSdkLog.printf("\n");
} else {
mSdkLog.printf("no skins.\n");
}
| private void | displayTargetList()Displays the list of available Targets (Platforms and Add-ons)
mSdkLog.printf("Available Android targets:\n");
int index = 1;
for (IAndroidTarget target : mSdkManager.getTargets()) {
mSdkLog.printf("id: %d\n", index);
mSdkLog.printf(" Name: %s\n", target.getName());
if (target.isPlatform()) {
mSdkLog.printf(" Type: Platform\n");
mSdkLog.printf(" API level: %d\n", target.getApiVersionNumber());
} else {
mSdkLog.printf(" Type: Add-On\n");
mSdkLog.printf(" Vendor: %s\n", target.getVendor());
if (target.getDescription() != null) {
mSdkLog.printf(" Description: %s\n", target.getDescription());
}
mSdkLog.printf(" Based on Android %s (API level %d)\n",
target.getApiVersionName(), target.getApiVersionNumber());
// display the optional libraries.
IOptionalLibrary[] libraries = target.getOptionalLibraries();
if (libraries != null) {
mSdkLog.printf(" Libraries:\n");
for (IOptionalLibrary library : libraries) {
mSdkLog.printf(" * %1$s (%2$s)\n",
library.getName(), library.getJarName());
mSdkLog.printf(String.format(
" %1$s\n", library.getDescription()));
}
}
}
// get the target skins
displaySkinList(target, " Skins: ");
index++;
}
| private void | doAction()Actually do an action...
String verb = mSdkCommandLine.getVerb();
String directObject = mSdkCommandLine.getDirectObject();
if (SdkCommandLine.VERB_LIST.equals(verb)) {
// list action.
if (SdkCommandLine.OBJECT_TARGET.equals(directObject)) {
displayTargetList();
} else if (SdkCommandLine.OBJECT_AVD.equals(directObject)) {
displayAvdList();
} else {
displayTargetList();
displayAvdList();
}
} else if (SdkCommandLine.VERB_CREATE.equals(verb) &&
SdkCommandLine.OBJECT_AVD.equals(directObject)) {
createAvd();
} else if (SdkCommandLine.VERB_DELETE.equals(verb) &&
SdkCommandLine.OBJECT_AVD.equals(directObject)) {
deleteAvd();
} else if (SdkCommandLine.VERB_MOVE.equals(verb) &&
SdkCommandLine.OBJECT_AVD.equals(directObject)) {
moveAvd();
} else if (SdkCommandLine.VERB_UPDATE.equals(verb) &&
SdkCommandLine.OBJECT_AVD.equals(directObject)) {
updateAvd();
} else if (SdkCommandLine.VERB_CREATE.equals(verb) &&
SdkCommandLine.OBJECT_PROJECT.equals(directObject)) {
createProject();
} else if (SdkCommandLine.VERB_UPDATE.equals(verb) &&
SdkCommandLine.OBJECT_PROJECT.equals(directObject)) {
updateProject();
} else {
mSdkCommandLine.printHelpAndExit(null);
}
| private void | errorAndExit(java.lang.String format, java.lang.Object args)
mSdkLog.error(null, format, args);
System.exit(1);
| private boolean | getBooleanReply(java.lang.String reply)Returns the boolean value represented by the string.
for (String valid : BOOLEAN_YES_REPLIES) {
if (valid.equalsIgnoreCase(reply)) {
return true;
}
}
for (String valid : BOOLEAN_NO_REPLIES) {
if (valid.equalsIgnoreCase(reply)) {
return false;
}
}
throw new IOException(String.format("%s is not a valid reply", reply));
| private java.lang.String | getProjectLocation(java.lang.String newProjectLocation)Adjusts the project location to make it absolute & canonical relative to the
working directory, if any.
// If the new project location is absolute, use it as-is
File projectDir = new File(newProjectLocation);
if (projectDir.isAbsolute()) {
return newProjectLocation;
}
// if there's no working directory, just use the project location as-is.
if (mWorkDir == null) {
return newProjectLocation;
}
// Combine then and get an absolute canonical directory
try {
projectDir = new File(mWorkDir, newProjectLocation).getCanonicalFile();
return projectDir.getPath();
} catch (IOException e) {
errorAndExit("Failed to combine working directory '%1$s' with project location '%2$s': %3$s",
mWorkDir.getPath(),
newProjectLocation,
e.getMessage());
return null;
}
| private void | init()Init the application by making sure the SDK path is available and
doing basic parsing of the SDK.
mSdkCommandLine = new SdkCommandLine(mSdkLog);
// We get passed a property for the tools dir
String toolsDirProp = System.getProperty(TOOLSDIR);
if (toolsDirProp == null) {
// for debugging, it's easier to override using the process environment
toolsDirProp = System.getenv(TOOLSDIR);
}
if (toolsDirProp != null) {
// got back a level for the SDK folder
File tools;
if (toolsDirProp.length() > 0) {
tools = new File(toolsDirProp);
mSdkFolder = tools.getParent();
} else {
try {
tools = new File(".").getCanonicalFile();
mSdkFolder = tools.getParent();
} catch (IOException e) {
// Will print an error below since mSdkFolder is not defined
}
}
}
if (mSdkFolder == null) {
errorAndExit("The tools directory property is not set, please make sure you are executing %1$s",
SdkConstants.androidCmdName());
}
// We might get passed a property for the working directory
// Either it is a valid directory and mWorkDir is set to it's absolute canonical value
// or mWorkDir remains null.
String workDirProp = System.getProperty(WORKDIR);
if (workDirProp == null) {
workDirProp = System.getenv(WORKDIR);
}
if (workDirProp != null) {
// This should be a valid directory
mWorkDir = new File(workDirProp);
try {
mWorkDir = mWorkDir.getCanonicalFile().getAbsoluteFile();
} catch (IOException e) {
mWorkDir = null;
}
if (mWorkDir == null || !mWorkDir.isDirectory()) {
errorAndExit("The working directory does not seem to be valid: '%1$s", workDirProp);
}
}
| public static void | main(java.lang.String[] args)
new Main().run(args);
| private void | moveAvd()Moves an AVD.
try {
String avdName = mSdkCommandLine.getParamName();
AvdManager avdManager = new AvdManager(mSdkManager, mSdkLog);
AvdInfo info = avdManager.getAvd(avdName, true /*validAvdOnly*/);
if (info == null) {
errorAndExit("There is no valid Android Virtual Device named '%s'.", avdName);
return;
}
// This is a rename if there's a new name for the AVD
String newName = mSdkCommandLine.getParamMoveNewName();
if (newName != null && newName.equals(info.getName())) {
// same name, not actually a rename operation
newName = null;
}
// This is a move (of the data files) if there's a new location path
String paramFolderPath = mSdkCommandLine.getParamLocationPath();
if (paramFolderPath != null) {
// check if paths are the same. Use File methods to account for OS idiosyncrasies.
try {
File f1 = new File(paramFolderPath).getCanonicalFile();
File f2 = new File(info.getPath()).getCanonicalFile();
if (f1.equals(f2)) {
// same canonical path, so not actually a move
paramFolderPath = null;
}
} catch (IOException e) {
// Fail to resolve canonical path. Fail now since a move operation might fail
// later and be harder to recover from.
errorAndExit(e.getMessage());
return;
}
}
if (newName == null && paramFolderPath == null) {
mSdkLog.warning("Move operation aborted: same AVD name, same canonical data path");
return;
}
// If a rename was requested and no data move was requested, check if the original
// data path is our default constructed from the AVD name. In this case we still want
// to rename that folder too.
if (newName != null && paramFolderPath == null) {
// Compute the original data path
File originalFolder = new File(
AndroidLocation.getFolder() + AndroidLocation.FOLDER_AVD,
info.getName() + AvdManager.AVD_FOLDER_EXTENSION);
if (originalFolder.equals(info.getPath())) {
try {
// The AVD is using the default data folder path based on the AVD name.
// That folder needs to be adjusted to use the new name.
File f = new File(AndroidLocation.getFolder() + AndroidLocation.FOLDER_AVD,
newName + AvdManager.AVD_FOLDER_EXTENSION);
paramFolderPath = f.getCanonicalPath();
} catch (IOException e) {
// Fail to resolve canonical path. Fail now rather than later.
errorAndExit(e.getMessage());
}
}
}
// Check for conflicts
if (newName != null) {
if (avdManager.getAvd(newName, false /*validAvdOnly*/) != null) {
errorAndExit("There is already an AVD named '%s'.", newName);
return;
}
File ini = info.getIniFile();
if (ini.equals(AvdInfo.getIniFile(newName))) {
errorAndExit("The AVD file '%s' is in the way.", ini.getCanonicalPath());
return;
}
}
if (paramFolderPath != null && new File(paramFolderPath).exists()) {
errorAndExit(
"There is already a file or directory at '%s'.\nUse --path to specify a different data folder.",
paramFolderPath);
}
avdManager.moveAvd(info, newName, paramFolderPath, mSdkLog);
} catch (AndroidLocationException e) {
errorAndExit(e.getMessage());
} catch (IOException e) {
errorAndExit(e.getMessage());
}
| private void | parseSdk()Does the basic SDK parsing required for all actions
mSdkManager = SdkManager.createManager(mSdkFolder, mSdkLog);
if (mSdkManager == null) {
errorAndExit("Unable to parse SDK content.");
}
| private java.util.Map | promptForHardware(com.android.sdklib.IAndroidTarget createTarget)Prompts the user to setup a hardware config for a Platform-based AVD.
byte[] readLineBuffer = new byte[256];
String result;
String defaultAnswer = "no";
mSdkLog.printf("%s is a basic Android platform.\n", createTarget.getName());
mSdkLog.printf("Do you wish to create a custom hardware profile [%s]",
defaultAnswer);
result = readLine(readLineBuffer).trim();
// handle default:
if (result.length() == 0) {
result = defaultAnswer;
}
if (getBooleanReply(result) == false) {
// no custom config.
return null;
}
mSdkLog.printf("\n"); // empty line
// get the list of possible hardware properties
File hardwareDefs = new File (mSdkFolder + File.separator +
SdkConstants.OS_SDK_TOOLS_LIB_FOLDER, SdkConstants.FN_HARDWARE_INI);
List<HardwareProperty> list = HardwareProperties.parseHardwareDefinitions(hardwareDefs,
null /*sdkLog*/);
HashMap<String, String> map = new HashMap<String, String>();
for (int i = 0 ; i < list.size() ;) {
HardwareProperty property = list.get(i);
String description = property.getDescription();
if (description != null) {
mSdkLog.printf("%s: %s\n", property.getAbstract(), description);
} else {
mSdkLog.printf("%s\n", property.getAbstract());
}
String defaultValue = property.getDefault();
if (defaultValue != null) {
mSdkLog.printf("%s [%s]:", property.getName(), defaultValue);
} else {
mSdkLog.printf("%s (%s):", property.getName(), property.getType());
}
result = readLine(readLineBuffer);
if (result.length() == 0) {
if (defaultValue != null) {
mSdkLog.printf("\n"); // empty line
i++; // go to the next property if we have a valid default value.
// if there's no default, we'll redo this property
}
continue;
}
switch (property.getType()) {
case BOOLEAN:
try {
if (getBooleanReply(result)) {
map.put(property.getName(), "yes");
i++; // valid reply, move to next property
} else {
map.put(property.getName(), "no");
i++; // valid reply, move to next property
}
} catch (IOException e) {
// display error, and do not increment i to redo this property
mSdkLog.printf("\n%s\n", e.getMessage());
}
break;
case INTEGER:
try {
Integer.parseInt(result);
map.put(property.getName(), result);
i++; // valid reply, move to next property
} catch (NumberFormatException e) {
// display error, and do not increment i to redo this property
mSdkLog.printf("\n%s\n", e.getMessage());
}
break;
case DISKSIZE:
// TODO check validity
map.put(property.getName(), result);
i++; // valid reply, move to next property
break;
}
mSdkLog.printf("\n"); // empty line
}
return map;
| private java.lang.String | readLine(byte[] buffer)Reads the line from the input stream.
int count = System.in.read(buffer);
// is the input longer than the buffer?
if (count == buffer.length && buffer[count-1] != 10) {
// create a new temp buffer
byte[] tempBuffer = new byte[256];
// and read the rest
String secondHalf = readLine(tempBuffer);
// return a concat of both
return new String(buffer, 0, count) + secondHalf;
}
// ignore end whitespace
while (count > 0 && (buffer[count-1] == '\r" || buffer[count-1] == '\n")) {
count--;
}
return new String(buffer, 0, count);
| private void | run(java.lang.String[] args)Runs the sdk manager app
createLogger();
init();
mSdkCommandLine.parseArgs(args);
parseSdk();
doAction();
| private void | updateAvd()Updates a broken AVD.
try {
String avdName = mSdkCommandLine.getParamName();
AvdManager avdManager = new AvdManager(mSdkManager, mSdkLog);
avdManager.updateAvd(avdName);
} catch (AndroidLocationException e) {
errorAndExit(e.getMessage());
} catch (IOException e) {
errorAndExit(e.getMessage());
}
| private void | updateProject()Updates an existing Android project based on command-line parameters
// get the target and try to resolve it.
IAndroidTarget target = null;
int targetId = mSdkCommandLine.getParamTargetId();
if (targetId >= 0) {
IAndroidTarget[] targets = mSdkManager.getTargets();
if (targetId < 1 || targetId > targets.length) {
errorAndExit("Target id is not valid. Use '%s list targets' to get the target ids.",
SdkConstants.androidCmdName());
}
target = targets[targetId - 1];
}
ProjectCreator creator = new ProjectCreator(mSdkFolder,
mSdkCommandLine.isVerbose() ? OutputLevel.VERBOSE :
mSdkCommandLine.isSilent() ? OutputLevel.SILENT :
OutputLevel.NORMAL,
mSdkLog);
String projectDir = getProjectLocation(mSdkCommandLine.getParamLocationPath());
creator.updateProject(projectDir,
target,
mSdkCommandLine.getParamName());
|
|