diff options
9 files changed, 205 insertions, 91 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutEditor.java index c059a41..a250c76 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutEditor.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutEditor.java @@ -505,7 +505,10 @@ public class LayoutEditor extends AndroidEditor implements IShowEditorInput, IPa IAndroidTarget target = currentSdk.getTarget(project); if (target != null) { AndroidTargetData data = currentSdk.getTargetData(target); - desc = data.getLayoutDescriptors().getBaseViewDescriptor(); + if (data != null) { + // data can be null when the target is still loading + desc = data.getLayoutDescriptors().getBaseViewDescriptor(); + } } } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/junit/AndroidJUnitLaunchAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/junit/AndroidJUnitLaunchAction.java index fcb859a..b398a05 100644 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/junit/AndroidJUnitLaunchAction.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/junit/AndroidJUnitLaunchAction.java @@ -25,6 +25,7 @@ import com.android.ide.eclipse.adt.internal.launch.junit.runtime.RemoteAdtTestRu import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; +import org.eclipse.core.runtime.IStatus; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchManager; @@ -33,6 +34,7 @@ import org.eclipse.debug.core.model.IStreamsProxy; import org.eclipse.jdt.junit.launcher.JUnitLaunchConfigurationDelegate; import org.eclipse.jdt.launching.IVMRunner; import org.eclipse.jdt.launching.VMRunnerConfiguration; +import org.eclipse.swt.widgets.Display; /** * A launch action that executes a instrumentation test run on an Android device. @@ -53,6 +55,8 @@ class AndroidJUnitLaunchAction implements IAndroidLaunchAction { /** * Launch a instrumentation test run on given Android device. * Reuses JDT JUnit launch delegate so results can be communicated back to JDT JUnit UI. + * <p/> + * Note: Must be executed on non-UI thread. * * @see IAndroidLaunchAction#doLaunchAction(DelayedLaunchInfo, IDevice) */ @@ -137,7 +141,7 @@ class AndroidJUnitLaunchAction implements IAndroidLaunchAction { } /** - * Provides a VM runner implementation which starts a thread implementation of a launch process + * Provides a VM runner implementation which starts a inline implementation of a launch process */ private static class VMTestRunner implements IVMRunner { @@ -156,15 +160,15 @@ class AndroidJUnitLaunchAction implements IAndroidLaunchAction { TestRunnerProcess runnerProcess = new TestRunnerProcess(config, mJUnitInfo); - runnerProcess.start(); launch.addProcess(runnerProcess); + runnerProcess.run(); } } /** * Launch process that executes the tests. */ - private static class TestRunnerProcess extends Thread implements IProcess { + private static class TestRunnerProcess implements IProcess { private final VMRunnerConfiguration mRunConfig; private final AndroidJUnitLaunchInfo mJUnitInfo; @@ -254,10 +258,18 @@ class AndroidJUnitLaunchAction implements IAndroidLaunchAction { } /** - * Launches a test runner that will communicate results back to JDT JUnit UI + * Launches a test runner that will communicate results back to JDT JUnit UI. + * <p/> + * Must be executed on a non-UI thread. */ - @Override public void run() { + if (Display.getCurrent() != null) { + AdtPlugin.log(IStatus.ERROR, "Adt test runner executed on UI thread"); + AdtPlugin.printErrorToConsole(mJUnitInfo.getProject(), + "Test launch failed due to internal error: Running tests on UI thread"); + terminate(); + return; + } mTestRunner = new RemoteAdtTestRunner(); mTestRunner.runTests(mRunConfig.getProgramArguments(), mJUnitInfo); } diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/junit/runtime/RemoteAdtTestRunner.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/junit/runtime/RemoteAdtTestRunner.java index 0a045bc..461fd9d 100755 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/junit/runtime/RemoteAdtTestRunner.java +++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/junit/runtime/RemoteAdtTestRunner.java @@ -33,7 +33,7 @@ import java.io.IOException; * Supports Eclipse JUnit execution of Android tests. * <p/> * Communicates back to a Eclipse JDT JUnit client via a socket connection. - * + * * @see org.eclipse.jdt.internal.junit.runner.RemoteTestRunner for more details on the protocol */ @SuppressWarnings("restriction") @@ -41,17 +41,17 @@ public class RemoteAdtTestRunner extends RemoteTestRunner { private AndroidJUnitLaunchInfo mLaunchInfo; private TestExecution mExecution; - + /** * Initialize the JDT JUnit test runner parameters from the {@code args}. - * - * @param args name-value pair of arguments to pass to parent JUnit runner. + * + * @param args name-value pair of arguments to pass to parent JUnit runner. * @param launchInfo the Android specific test launch info */ protected void init(String[] args, AndroidJUnitLaunchInfo launchInfo) { defaultInit(args); mLaunchInfo = launchInfo; - } + } /** * Runs a set of tests, and reports back results using parent class. @@ -65,13 +65,13 @@ public class RemoteAdtTestRunner extends RemoteTestRunner { * <li>The test execution result for each test method. Expects individual notifications of * the test execution start, any failures, and the end of the test execution.</li> * <li>The end of the test run, with its elapsed time.</li> - * </ol> + * </ol> * <p/> * In order to satisfy this, this method performs two actual Android instrumentation runs. * The first is a 'log only' run that will collect the test tree data, without actually * executing the tests, and send it back to JDT JUnit. The second is the actual test execution, * whose results will be communicated back in real-time to JDT JUnit. - * + * * @param testClassNames ignored - the AndroidJUnitLaunchInfo will be used to determine which * tests to run. * @param testName ignored @@ -81,16 +81,16 @@ public class RemoteAdtTestRunner extends RemoteTestRunner { public void runTests(String[] testClassNames, String testName, TestExecution execution) { // hold onto this execution reference so it can be used to report test progress mExecution = execution; - - RemoteAndroidTestRunner runner = new RemoteAndroidTestRunner(mLaunchInfo.getAppPackage(), - mLaunchInfo.getRunner(), mLaunchInfo.getDevice()); + + RemoteAndroidTestRunner runner = new RemoteAndroidTestRunner(mLaunchInfo.getAppPackage(), + mLaunchInfo.getRunner(), mLaunchInfo.getDevice()); if (mLaunchInfo.getTestClass() != null) { if (mLaunchInfo.getTestMethod() != null) { runner.setMethodName(mLaunchInfo.getTestClass(), mLaunchInfo.getTestMethod()); - } else { + } else { runner.setClassName(mLaunchInfo.getTestClass()); - } + } } if (mLaunchInfo.getTestPackage() != null) { @@ -102,6 +102,8 @@ public class RemoteAdtTestRunner extends RemoteTestRunner { runner.setLogOnly(true); TestCollector collector = new TestCollector(); try { + AdtPlugin.printToConsole(mLaunchInfo.getProject(), "Collecting test information"); + runner.run(collector); if (collector.getErrorMessage() != null) { // error occurred during test collection. @@ -111,6 +113,9 @@ public class RemoteAdtTestRunner extends RemoteTestRunner { return; } notifyTestRunStarted(collector.getTestCaseCount()); + AdtPlugin.printToConsole(mLaunchInfo.getProject(), + "Sending test information to Eclipse"); + collector.sendTrees(this); // now do real execution @@ -118,23 +123,24 @@ public class RemoteAdtTestRunner extends RemoteTestRunner { if (mLaunchInfo.isDebugMode()) { runner.setDebug(true); } + AdtPlugin.printToConsole(mLaunchInfo.getProject(), "Running tests..."); runner.run(new TestRunListener()); } catch (IOException e) { reportError(String.format(LaunchMessages.RemoteAdtTestRunner_RunIOException_s, e.getMessage())); } } - + /** * Main entry method to run tests - * + * * @param programArgs JDT JUnit program arguments to be processed by parent * @param junitInfo the {@link AndroidJUnitLaunchInfo} containing info about this test ru */ public void runTests(String[] programArgs, AndroidJUnitLaunchInfo junitInfo) { init(programArgs, junitInfo); run(); - } + } /** * Stop the current test run. @@ -147,7 +153,7 @@ public class RemoteAdtTestRunner extends RemoteTestRunner { protected void stop() { if (mExecution != null) { mExecution.stop(); - } + } } private void notifyTestRunEnded(long elapsedTime) { @@ -161,14 +167,14 @@ public class RemoteAdtTestRunner extends RemoteTestRunner { * @param errorMessage */ private void reportError(String errorMessage) { - AdtPlugin.printErrorToConsole(mLaunchInfo.getProject(), + AdtPlugin.printErrorToConsole(mLaunchInfo.getProject(), String.format(LaunchMessages.RemoteAdtTestRunner_RunFailedMsg_s, errorMessage)); // is this needed? //notifyTestRunStopped(-1); } /** - * TestRunListener that communicates results in real-time back to JDT JUnit + * TestRunListener that communicates results in real-time back to JDT JUnit */ private class TestRunListener implements ITestRunListener { @@ -189,8 +195,8 @@ public class RemoteAdtTestRunner extends RemoteTestRunner { } else { statusString = MessageIds.TEST_FAILED; } - TestReferenceFailure failure = - new TestReferenceFailure(new TestCaseReference(test), + TestReferenceFailure failure = + new TestReferenceFailure(new TestCaseReference(test), statusString, trace, null); mExecution.getListener().notifyTestFailed(failure); } @@ -234,5 +240,33 @@ public class RemoteAdtTestRunner extends RemoteTestRunner { TestCaseReference testId = new TestCaseReference(test); mExecution.getListener().notifyTestStarted(testId); } + + } + + /** + * Override parent to get extra logs. + */ + @Override + protected boolean connect() { + boolean result = super.connect(); + if (!result) { + AdtPlugin.printErrorToConsole(mLaunchInfo.getProject(), + "Connect to Eclipse test result listener failed"); + } + return result; + } + + /** + * Override parent to dump error message to console. + */ + @Override + public void runFailed(String message, Exception exception) { + if (exception != null) { + AdtPlugin.logAndPrintError(exception, mLaunchInfo.getProject().getName(), + "Test launch failed: %s", message); + } else { + AdtPlugin.printErrorToConsole(mLaunchInfo.getProject(), "Test launch failed: %s", + message); + } } }
\ No newline at end of file diff --git a/eclipse/scripts/build_server.sh b/eclipse/scripts/build_server.sh index cd4f1ac..75111f4 100755 --- a/eclipse/scripts/build_server.sh +++ b/eclipse/scripts/build_server.sh @@ -61,8 +61,8 @@ function check_params() { function build_libs() { MAKE_OPT="-j8" - echo "*** Building: make $MAKE_OPT dx ping ddms jarutils androidprefs layoutlib_api ninepatch sdklib sdkuilib" - make $MAKE_OPT dx ping ddms jarutils androidprefs layoutlib_api layoutlib_utils ninepatch sdklib sdkuilib + echo "*** Building: make $MAKE_OPT dx ping ddms jarutils androidprefs groovy-all-1.7.0 layoutlib layoutlib_api layoutlib_utils ninepatch sdklib sdkuilib" + make $MAKE_OPT dx ping ddms jarutils androidprefs groovy-all-1.7.0 layoutlib layoutlib_api layoutlib_utils ninepatch sdklib sdkuilib } function build_plugin { diff --git a/files/ant_rules_r3.xml b/files/ant_rules_r3.xml index 82abb6d..76f54e4 100644 --- a/files/ant_rules_r3.xml +++ b/files/ant_rules_r3.xml @@ -81,7 +81,7 @@ <property name="out.release.package" location="${out.absolute.dir}/${ant.project.name}-release.apk" /> - <!-- set some property used for filtering/override. If those weren't defined + <!-- set some properties used for filtering/override. If those weren't defined before, then this will create them with empty values, which are then ignored by the custom tasks receiving them. --> <property name="version.code" value="" /> @@ -216,8 +216,12 @@ <mkdir dir="${out.classes.absolute.dir}" /> </target> + <!-- empty default pre-build target. Create a similar target in + your build.xml and it'll be called instead of this one. --> + <target name="-pre-build"/> + <!-- Generates the R.java file for this project's resources. --> - <target name="-resource-src" depends="-dirs"> + <target name="-resource-src" depends="-dirs, -pre-build"> <echo>Generating R.java / Manifest.java from the resources...</echo> <aaptexec executable="${aapt}" command="package" @@ -242,8 +246,12 @@ </apply> </target> + <!-- empty default pre-compile target. Create a similar target in + your build.xml and it'll be called instead of this one. --> + <target name="-pre-compile"/> + <!-- Compiles this project's .java files into .class files. --> - <target name="compile" depends="-resource-src, -aidl" + <target name="compile" depends="-resource-src, -aidl, -pre-compile" description="Compiles project's .java files into .class files"> <!-- If android rules are used for a test project, its classpath should include tested project's location --> @@ -270,8 +278,12 @@ </javac> </target> + <!-- empty default post-compile target. Create a similar target in + your build.xml and it'll be called instead of this one. --> + <target name="-post-compile"/> + <!-- Converts this project's .class files into .dex files --> - <target name="-dex" depends="compile"> + <target name="-dex" depends="compile, -post-compile"> <dex-helper /> </target> diff --git a/sdklauncher/sdklauncher.c b/sdklauncher/sdklauncher.c index 23b785d..e1d97a1 100644 --- a/sdklauncher/sdklauncher.c +++ b/sdklauncher/sdklauncher.c @@ -29,9 +29,24 @@ #ifdef _WIN32 #include <stdio.h> +#include <stdarg.h> +#include <string.h> #include <windows.h> +int _enable_dprintf = 0; + +void dprintf(char *msg, ...) { + va_list ap; + va_start(ap, msg); + + if (_enable_dprintf) { + vfprintf(stderr, msg, ap); + } + + va_end(ap); +} + void display_error(LPSTR description) { DWORD err = GetLastError(); LPSTR s, s2; @@ -170,8 +185,8 @@ int sdk_launcher() { int result = 0; STARTUPINFO startup; PROCESS_INFORMATION pinfo; - CHAR program_path[MAX_PATH]; - int ret; + CHAR program_dir[MAX_PATH]; + int ret, pos; CHAR temp_filename[MAX_PATH]; HANDLE temp_handle; @@ -189,29 +204,50 @@ int sdk_launcher() { startup.hStdOutput = temp_handle; startup.hStdError = temp_handle; - /* get path of current program */ - GetModuleFileName(NULL, program_path, sizeof(program_path)); - - ret = CreateProcess( - NULL, /* program path */ - "tools\\android.bat update sdk", /* command-line */ - NULL, /* process handle is not inheritable */ - NULL, /* thread handle is not inheritable */ - TRUE, /* yes, inherit some handles */ - CREATE_NO_WINDOW, /* we don't want a console */ - NULL, /* use parent's environment block */ - NULL, /* use parent's starting directory */ - &startup, /* startup info, i.e. std handles */ - &pinfo); - - if (!ret) { - display_error("Failed to execute tools\\android.bat:"); + /* get path of current program, to switch dirs here when executing the command. */ + ret = GetModuleFileName(NULL, program_dir, sizeof(program_dir)); + if (ret == 0) { + display_error("Failed to get program's filename:"); result = 1; } else { - WaitForSingleObject(pinfo.hProcess, INFINITE); - CloseHandle(pinfo.hProcess); - CloseHandle(pinfo.hThread); + /* Remove the last segment to keep only the directory. */ + pos = ret - 1; + while (pos > 0 && program_dir[pos] != '\\') { + --pos; + } + program_dir[pos] = 0; + } + + if (!result) { + dprintf("Program dir: %s\n", program_dir); + + ret = CreateProcess( + NULL, /* program path */ + "tools\\android.bat update sdk", /* command-line */ + NULL, /* process handle is not inheritable */ + NULL, /* thread handle is not inheritable */ + TRUE, /* yes, inherit some handles */ + CREATE_NO_WINDOW, /* we don't want a console */ + NULL, /* use parent's environment block */ + program_dir, /* use parent's starting directory */ + &startup, /* startup info, i.e. std handles */ + &pinfo); + + dprintf("CreateProcess returned %d\n", ret); + + if (!ret) { + display_error("Failed to execute tools\\android.bat:"); + result = 1; + } else { + dprintf("Wait for process to finish.\n"); + + WaitForSingleObject(pinfo.hProcess, INFINITE); + CloseHandle(pinfo.hProcess); + CloseHandle(pinfo.hThread); + } } + + dprintf("Cleanup.\n"); if (!CloseHandle(temp_handle)) { display_error("CloseHandle temp file failed"); @@ -229,6 +265,9 @@ int sdk_launcher() { } int main(int argc, char **argv) { + _enable_dprintf = argc > 1 && strcmp(argv[1], "-v") == 0; + dprintf("Verbose debug mode.\n"); + return sdk_launcher(); } diff --git a/sdkmanager/app/src/com/android/sdkmanager/CommandLineProcessor.java b/sdkmanager/app/src/com/android/sdkmanager/CommandLineProcessor.java index d24bed4..6536baa 100644 --- a/sdkmanager/app/src/com/android/sdkmanager/CommandLineProcessor.java +++ b/sdkmanager/app/src/com/android/sdkmanager/CommandLineProcessor.java @@ -115,7 +115,7 @@ class CommandLineProcessor { "Silent mode: only errors are printed out.", false); define(Mode.BOOLEAN, false, GLOBAL_FLAG_VERB, NO_VERB_OBJECT, "h", KEY_HELP, - "This help.", + "Help on a specific command.", false); } diff --git a/sdkmanager/app/src/com/android/sdkmanager/Main.java b/sdkmanager/app/src/com/android/sdkmanager/Main.java index 58a9a98..49eee7e 100644 --- a/sdkmanager/app/src/com/android/sdkmanager/Main.java +++ b/sdkmanager/app/src/com/android/sdkmanager/Main.java @@ -232,6 +232,10 @@ public class Main { updateTestProject(); } else if (SdkCommandLine.OBJECT_LIB_PROJECT.equals(directObject)) { updateProject(true /*library*/); + } else if (SdkCommandLine.OBJECT_SDK.equals(directObject)) { + showMainWindow(true /*autoUpdate*/); + } else if (SdkCommandLine.OBJECT_ADB.equals(directObject)) { + updateAdb(); } } else if (SdkCommandLine.VERB_DELETE.equals(verb) && SdkCommandLine.OBJECT_AVD.equals(directObject)) { @@ -244,14 +248,6 @@ public class Main { } else if (verb == null && directObject == null) { showMainWindow(false /*autoUpdate*/); - } else if (SdkCommandLine.VERB_UPDATE.equals(verb) && - SdkCommandLine.OBJECT_SDK.equals(directObject)) { - showMainWindow(true /*autoUpdate*/); - - } else if (SdkCommandLine.VERB_UPDATE.equals(verb) && - SdkCommandLine.OBJECT_ADB.equals(directObject)) { - updateAdb(); - } else { mSdkCommandLine.printHelpAndExit(null); } diff --git a/templates/build.template b/templates/build.template index 3959c57..549ce7c 100644 --- a/templates/build.template +++ b/templates/build.template @@ -1,40 +1,42 @@ <?xml version="1.0" encoding="UTF-8"?> <project name="PROJECT_NAME" default="help"> - <!-- The local.properties file is created and updated by the 'android' tool. - It contains the path to the SDK. It should *NOT* be checked in in Version - Control Systems. --> +<!-- The local.properties file is created and updated by the 'android' + tool. + It contains the path to the SDK. It should *NOT* be checked in in + Version Control Systems. --> <property file="local.properties" /> <!-- The build.properties file can be created by you and is never touched - by the 'android' tool. This is the place to change some of the default property values - used by the Ant rules. + by the 'android' tool. This is the place to change some of the + default property values used by the Ant rules. Here are some properties you may want to change/update: application.package - the name of your application package as defined in the manifest. Used by the - 'uninstall' rule. + The name of your application package as defined in the manifest. + Used by the 'uninstall' rule. source.dir - the name of the source directory. Default is 'src'. + The name of the source directory. Default is 'src'. out.dir - the name of the output directory. Default is 'bin'. + The name of the output directory. Default is 'bin'. - Properties related to the SDK location or the project target should be updated - using the 'android' tool with the 'update' action. + Properties related to the SDK location or the project target should + be updated using the 'android' tool with the 'update' action. - This file is an integral part of the build system for your application and - should be checked in in Version Control Systems. + This file is an integral part of the build system for your + application and should be checked in in Version Control Systems. --> <property file="build.properties" /> - <!-- The default.properties file is created and updated by the 'android' tool, as well - as ADT. - This file is an integral part of the build system for your application and - should be checked in in Version Control Systems. --> + <!-- The default.properties file is created and updated by the 'android' + tool, as well as ADT. + This file is an integral part of the build system for your + application and should be checked in in Version Control Systems. --> <property file="default.properties" /> - <!-- Custom Android task to deal with the project target, and import the proper rules. + <!-- Custom Android task to deal with the project target, and import the + proper rules. This requires ant 1.6.0 or above. --> <path id="android.antlibs"> <pathelement path="${sdk.dir}/tools/lib/anttasks.jar" /> @@ -48,19 +50,35 @@ classname="com.android.ant.SetupTask" classpathref="android.antlibs" /> - <!-- Execute the Android Setup task that will setup some properties specific to the target, - and import the build rules files. +<!-- extension targets. Uncomment the ones where you want to do custom work + in between standard targets --> +<!-- + <target name="-pre-build"> + </target> + <target name="-pre-compile"> + </target> + <target name="-post-compile"> + </target> +--> - The rules file is imported from - <SDK>/platforms/<target_platform>/templates/android_rules.xml - To customize some build steps for your project: - - copy the content of the main node <project> from android_rules.xml - - paste it in this build.xml below the <setup /> task. - - disable the import by changing the setup task below to <setup import="false" /> + <!-- Execute the Android Setup task that will setup some properties + specific to the target, and import the build rules files. + + The rules file is imported from + <SDK>/platforms/<target_platform>/ant/ant_rules_r#.xml - This will ensure that the properties are setup correctly but that your customized - build steps are used. + To customize existing targets, there are two options: + - Customize only one target: + - copy/paste the target into this file, *before* the + <setup> task. + - customize it to your needs. + - Customize the whole script. + - copy/paste the content of the rules files (minus the top node) + into this file, *after* the <setup> task + - disable the import of the rules by changing the setup task + below to <setup import="false" />. + - customize to your needs. --> <setup /> |