aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/IRemoteAndroidTestRunner.java60
-rwxr-xr-xddms/libs/ddmlib/src/com/android/ddmlib/testrunner/InstrumentationResultParser.java5
-rw-r--r--ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunner.java24
-rw-r--r--ddms/libs/ddmlib/tests/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunnerTest.java10
-rw-r--r--dumpeventlog/.gitignore1
-rw-r--r--eclipse/features/com.android.ide.eclipse.adt/feature.xml2
-rw-r--r--eclipse/features/com.android.ide.eclipse.ddms/feature.xml2
-rw-r--r--eclipse/features/com.android.ide.eclipse.tests/feature.xml2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java20
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ApkBuilder.java37
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/LibraryDeltaVisitor.java11
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ResourceManagerBuilder.java4
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidEditor.java16
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ExplodedRenderingHelper.java2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/LayoutEditor.java35
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationComposite.java12
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/pages/OverviewExportPart.java98
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/LaunchMessages.java2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/LaunchShortcut.java18
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/MainLaunchConfigTab.java3
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/junit/AndroidJUnitLaunchConfigurationTab.java3
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/junit/runtime/RemoteAdtTestRunner.java41
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/messages.properties1
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ProjectChooserHelper.java9
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ProjectState.java6
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/properties/LibraryProperties.java6
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/actions/ExportAction.java16
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/actions/ExportWizardAction.java42
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/ProjectCheckPage.java3
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectWizard.java77
-rwxr-xr-xeclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewTestProjectCreationPage.java3
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java3
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.ddms/META-INF/MANIFEST.MF2
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.tests/META-INF/MANIFEST.MF2
-rw-r--r--eclipse/sites/external/site.xml4
-rw-r--r--eclipse/sites/internal/site.xml6
-rw-r--r--emulator/gps/Android.mk30
-rw-r--r--emulator/gps/gps_qemu.c941
-rw-r--r--emulator/mksdcard/MODULE_LICENSE_BSD0
-rw-r--r--emulator/mksdcard/NOTICE23
-rw-r--r--eventanalyzer/.gitignore1
-rw-r--r--files/ant_rules_r1.xml5
-rw-r--r--files/ant_rules_r2.xml5
-rw-r--r--files/ant_test_rules_r2.xml2
-rw-r--r--files/tools_source.properties2
-rwxr-xr-xsdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSource.java51
-rwxr-xr-xsdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RemotePackagesPage.java48
-rw-r--r--sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdCreationDialog.java29
49 files changed, 1549 insertions, 178 deletions
diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/IRemoteAndroidTestRunner.java b/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/IRemoteAndroidTestRunner.java
index 75c8eeb..b40f164 100644
--- a/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/IRemoteAndroidTestRunner.java
+++ b/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/IRemoteAndroidTestRunner.java
@@ -16,6 +16,7 @@
package com.android.ddmlib.testrunner;
+import java.io.IOException;
import java.util.Collection;
/**
@@ -23,6 +24,51 @@ import java.util.Collection;
*/
public interface IRemoteAndroidTestRunner {
+ public static enum TestSize {
+ /** Run tests annotated with SmallTest */
+ SMALL("small"),
+ /** Run tests annotated with MediumTest */
+ MEDIUM("medium"),
+ /** Run tests annotated with LargeTest */
+ LARGE("large");
+
+ private String mRunnerValue;
+
+ /**
+ * Create a {@link TestSize}.
+ *
+ * @param runnerValue the {@link String} value that represents the size that is passed to
+ * device. Defined on device in android.test.InstrumentationTestRunner.
+ */
+ TestSize(String runnerValue) {
+ mRunnerValue = runnerValue;
+ }
+
+ String getRunnerValue() {
+ return mRunnerValue;
+ }
+
+ /**
+ * Return the {@link TestSize} corresponding to the given Android platform defined value.
+ *
+ * @throws IllegalArgumentException if {@link TestSize} cannot be found.
+ */
+ public static TestSize getTestSize(String value) {
+ // build the error message in the success case too, to avoid two for loops
+ StringBuilder msgBuilder = new StringBuilder("Unknown TestSize ");
+ msgBuilder.append(value);
+ msgBuilder.append(", Must be one of ");
+ for (TestSize size : values()) {
+ if (size.getRunnerValue().equals(value)) {
+ return size;
+ }
+ msgBuilder.append(size.getRunnerValue());
+ msgBuilder.append(", ");
+ }
+ throw new IllegalArgumentException(msgBuilder.toString());
+ }
+ }
+
/**
* Returns the application package name.
*/
@@ -70,6 +116,14 @@ public interface IRemoteAndroidTestRunner {
public void setTestPackageName(String packageName);
/**
+ * Sets to run only tests of given size.
+ * Must be called before 'run'.
+ *
+ * @param size the {@link TestSize} to run.
+ */
+ public void setTestSize(TestSize size);
+
+ /**
* Adds a argument to include in instrumentation command.
* <p/>
* Must be called before 'run'. If an argument with given name has already been provided, it's
@@ -112,15 +166,17 @@ public interface IRemoteAndroidTestRunner {
* Convenience method for {@link #run(Collection)}.
*
* @param listeners listens for test results
+ * @throws IOException if connection to device was lost.
*/
- public void run(ITestRunListener... listeners);
+ public void run(ITestRunListener... listeners) throws IOException;
/**
* Execute this test run.
*
* @param listeners collection of listeners for test results
+ * @throws IOException if connection to device was lost.
*/
- public void run(Collection<ITestRunListener> listeners);
+ public void run(Collection<ITestRunListener> listeners) throws IOException;
/**
* Requests cancellation of this test run.
diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/InstrumentationResultParser.java b/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/InstrumentationResultParser.java
index 708377e..2bc5710 100755
--- a/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/InstrumentationResultParser.java
+++ b/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/InstrumentationResultParser.java
@@ -234,8 +234,8 @@ public class InstrumentationResultParser extends MultiLineReceiver {
// this is a value that has wrapped to next line.
mCurrentValue.append("\r\n");
mCurrentValue.append(line);
- } else {
- Log.i(LOG_TAG, "unrecognized line " + line);
+ } else if (line.trim().length() > 0){
+ Log.d(LOG_TAG, "unrecognized line " + line);
}
}
}
@@ -462,7 +462,6 @@ public class InstrumentationResultParser extends MultiLineReceiver {
listener.testRunFailed(errorMsg);
}
mTestRunFailReported = true;
-
}
/**
diff --git a/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunner.java b/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunner.java
index f45d267..0d22886 100644
--- a/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunner.java
+++ b/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunner.java
@@ -52,6 +52,7 @@ public class RemoteAndroidTestRunner implements IRemoteAndroidTestRunner {
private static final String DEBUG_ARG_NAME = "debug";
private static final String COVERAGE_ARG_NAME = "coverage";
private static final String PACKAGE_ARG_NAME = "package";
+ private static final String SIZE_ARG_NAME = "size";
/**
* Creates a remote Android test runner.
@@ -183,27 +184,28 @@ public class RemoteAndroidTestRunner implements IRemoteAndroidTestRunner {
/**
* {@inheritDoc}
*/
- public void run(ITestRunListener... listeners) {
+ public void setTestSize(TestSize size) {
+ addInstrumentationArg(SIZE_ARG_NAME, size.getRunnerValue());
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void run(ITestRunListener... listeners) throws IOException {
run(Arrays.asList(listeners));
}
/**
* {@inheritDoc}
*/
- public void run(Collection<ITestRunListener> listeners) {
+ public void run(Collection<ITestRunListener> listeners) throws IOException {
final String runCaseCommandStr = String.format("am instrument -w -r %s %s",
getArgsCommand(), getRunnerPath());
- Log.d(LOG_TAG, runCaseCommandStr);
+ Log.i(LOG_TAG, String.format("Running %s on %s", runCaseCommandStr,
+ mRemoteDevice.getSerialNumber()));
mParser = new InstrumentationResultParser(listeners);
- try {
- mRemoteDevice.executeShellCommand(runCaseCommandStr, mParser);
- } catch (IOException e) {
- Log.e(LOG_TAG, e);
- for (ITestRunListener listener : listeners) {
- listener.testRunFailed(e.toString());
- }
- }
+ mRemoteDevice.executeShellCommand(runCaseCommandStr, mParser);
}
/**
diff --git a/ddms/libs/ddmlib/tests/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunnerTest.java b/ddms/libs/ddmlib/tests/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunnerTest.java
index 02a6b7d..f9af29a 100644
--- a/ddms/libs/ddmlib/tests/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunnerTest.java
+++ b/ddms/libs/ddmlib/tests/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunnerTest.java
@@ -52,7 +52,7 @@ public class RemoteAndroidTestRunnerTest extends TestCase {
/**
* Test the basic case building of the instrumentation runner command with no arguments.
*/
- public void testRun() {
+ public void testRun() throws IOException {
mRunner.run(new EmptyListener());
assertStringsEquals(String.format("am instrument -w -r %s/%s", TEST_PACKAGE, TEST_RUNNER),
mMockDevice.getLastShellCommand());
@@ -61,7 +61,7 @@ public class RemoteAndroidTestRunnerTest extends TestCase {
/**
* Test the building of the instrumentation runner command with log set.
*/
- public void testRunWithLog() {
+ public void testRunWithLog() throws IOException {
mRunner.setLogOnly(true);
mRunner.run(new EmptyListener());
assertStringsEquals(String.format("am instrument -w -r -e log true %s/%s", TEST_PACKAGE,
@@ -71,7 +71,7 @@ public class RemoteAndroidTestRunnerTest extends TestCase {
/**
* Test the building of the instrumentation runner command with method set.
*/
- public void testRunWithMethod() {
+ public void testRunWithMethod() throws IOException {
final String className = "FooTest";
final String testName = "fooTest";
mRunner.setMethodName(className, testName);
@@ -83,7 +83,7 @@ public class RemoteAndroidTestRunnerTest extends TestCase {
/**
* Test the building of the instrumentation runner command with test package set.
*/
- public void testRunWithPackage() {
+ public void testRunWithPackage() throws IOException {
final String packageName = "foo.test";
mRunner.setTestPackageName(packageName);
mRunner.run(new EmptyListener());
@@ -94,7 +94,7 @@ public class RemoteAndroidTestRunnerTest extends TestCase {
/**
* Test the building of the instrumentation runner command with extra argument added.
*/
- public void testRunWithAddInstrumentationArg() {
+ public void testRunWithAddInstrumentationArg() throws IOException {
final String extraArgName = "blah";
final String extraArgValue = "blahValue";
mRunner.addInstrumentationArg(extraArgName, extraArgValue);
diff --git a/dumpeventlog/.gitignore b/dumpeventlog/.gitignore
new file mode 100644
index 0000000..ba077a4
--- /dev/null
+++ b/dumpeventlog/.gitignore
@@ -0,0 +1 @@
+bin
diff --git a/eclipse/features/com.android.ide.eclipse.adt/feature.xml b/eclipse/features/com.android.ide.eclipse.adt/feature.xml
index e182bb4..f164148 100644
--- a/eclipse/features/com.android.ide.eclipse.adt/feature.xml
+++ b/eclipse/features/com.android.ide.eclipse.adt/feature.xml
@@ -2,7 +2,7 @@
<feature
id="com.android.ide.eclipse.adt"
label="Android Development Tools"
- version="0.9.7.qualifier"
+ version="0.9.8.qualifier"
provider-name="The Android Open Source Project"
plugin="com.android.ide.eclipse.adt">
diff --git a/eclipse/features/com.android.ide.eclipse.ddms/feature.xml b/eclipse/features/com.android.ide.eclipse.ddms/feature.xml
index b78c86c..8535b9d 100644
--- a/eclipse/features/com.android.ide.eclipse.ddms/feature.xml
+++ b/eclipse/features/com.android.ide.eclipse.ddms/feature.xml
@@ -2,7 +2,7 @@
<feature
id="com.android.ide.eclipse.ddms"
label="Android DDMS"
- version="0.9.7.qualifier"
+ version="0.9.8.qualifier"
provider-name="The Android Open Source Project">
<description>
diff --git a/eclipse/features/com.android.ide.eclipse.tests/feature.xml b/eclipse/features/com.android.ide.eclipse.tests/feature.xml
index 474e81c..2c17001 100644
--- a/eclipse/features/com.android.ide.eclipse.tests/feature.xml
+++ b/eclipse/features/com.android.ide.eclipse.tests/feature.xml
@@ -2,7 +2,7 @@
<feature
id="com.android.ide.eclipse.tests"
label="ADT Tests"
- version="0.9.7.qualifier"
+ version="0.9.8.qualifier"
provider-name="The Android Open Source Project">
<copyright>
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF b/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF
index 5e8197e..549bd90 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Android Development Toolkit
Bundle-SymbolicName: com.android.ide.eclipse.adt;singleton:=true
-Bundle-Version: 0.9.7.qualifier
+Bundle-Version: 0.9.8.qualifier
Bundle-ClassPath: .,
jarutils.jar,
androidprefs.jar,
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java
index 6208b45..a9336b2 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java
@@ -507,7 +507,8 @@ public class AdtPlugin extends AbstractUIPlugin {
return total.toString();
}
} catch (IOException e) {
- // we'll just return null;.
+ // we'll just return null
+ AdtPlugin.log(e, "Failed to read text file '%s'", filepath); //$NON-NLS-1$
}
return null;
@@ -538,6 +539,7 @@ public class AdtPlugin extends AbstractUIPlugin {
}
} catch (IOException e) {
// we'll just return null;.
+ AdtPlugin.log(e, "Failed to read binary file '%s'", filepath); //$NON-NLS-1$
}
return null;
@@ -558,8 +560,10 @@ public class AdtPlugin extends AbstractUIPlugin {
}
} catch (MalformedURLException e) {
// we'll just return null.
+ AdtPlugin.log(e, "Failed to read stream '%s'", filepath); //$NON-NLS-1$
} catch (IOException e) {
// we'll just return null;.
+ AdtPlugin.log(e, "Failed to read stream '%s'", filepath); //$NON-NLS-1$
}
return null;
@@ -576,12 +580,24 @@ public class AdtPlugin extends AbstractUIPlugin {
if (sPlugin != null) {
bundle = sPlugin.getBundle();
} else {
+ AdtPlugin.log(IStatus.WARNING, "ADT Plugin is missing"); //$NON-NLS-1$
return null;
}
}
// attempt to get a file to one of the template.
- return bundle.getEntry(AndroidConstants.WS_SEP + filepath);
+ String path = filepath;
+ if (!path.startsWith(AndroidConstants.WS_SEP)) {
+ path = AndroidConstants.WS_SEP + path;
+ }
+
+ URL url = bundle.getEntry(path);
+
+ if (url == null) {
+ AdtPlugin.log(IStatus.INFO, "Bundle file URL not found at path '%s'", path); //$NON-NLS-1$
+ }
+
+ return url;
}
/**
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ApkBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ApkBuilder.java
index 979f6b1..ad20e5b 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ApkBuilder.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ApkBuilder.java
@@ -343,17 +343,18 @@ public class ApkBuilder extends BaseBuilder {
// if the main resources didn't change, then we check for the library
// ones (will trigger resource repackaging too)
- if (mPackageResources == false && libProjects != null &&
- libProjects.length > 0) {
+ if ((mPackageResources == false || mBuildFinalPackage == false) &&
+ libProjects != null && libProjects.length > 0) {
for (IProject libProject : libProjects) {
delta = getDelta(libProject);
if (delta != null) {
LibraryDeltaVisitor visitor = new LibraryDeltaVisitor();
delta.accept(visitor);
- mPackageResources = visitor.getResChange();
+ mPackageResources |= visitor.getResChange();
+ mBuildFinalPackage |= visitor.getLibChange();
- if (mPackageResources) {
+ if (mPackageResources && mBuildFinalPackage) {
break;
}
}
@@ -660,7 +661,7 @@ public class ApkBuilder extends BaseBuilder {
String classesDexPath = osBinPath + File.separator +
AndroidConstants.FN_CLASSES_DEX;
if (finalPackage(osBinPath + File.separator + AndroidConstants.FN_RESOURCES_AP_,
- classesDexPath,osFinalPackagePath, javaProject,
+ classesDexPath, osFinalPackagePath, javaProject, libProjects,
referencedJavaProjects, debuggable) == false) {
return allRefProjects;
}
@@ -678,7 +679,7 @@ public class ApkBuilder extends BaseBuilder {
String apkOsFilePath = osBinPath + File.separator +
ProjectHelper.getApkFilename(project, entry.getKey());
if (finalPackage(resPath, classesDexPath, apkOsFilePath, javaProject,
- referencedJavaProjects, debuggable) == false) {
+ libProjects, referencedJavaProjects, debuggable) == false) {
return allRefProjects;
}
}
@@ -946,14 +947,16 @@ public class ApkBuilder extends BaseBuilder {
* @param intermediateApk The path to the temporary resource file.
* @param dex The path to the dex file.
* @param output The path to the final package file to create.
- * @param javaProject
- * @param referencedJavaProjects
- * @param debuggable
+ * @param javaProject the java project being compiled
+ * @param libProjects an optional list of library projects (can be null)
+ * @param referencedJavaProjects referenced projects.
+ * @param debuggable whether the project manifest has debuggable==true. If true, any gdbserver
+ * executables will be packaged with the native libraries.
* @return true if success, false otherwise.
*/
private boolean finalPackage(String intermediateApk, String dex, String output,
- final IJavaProject javaProject, IJavaProject[] referencedJavaProjects,
- boolean debuggable) {
+ final IJavaProject javaProject, IProject[] libProjects,
+ IJavaProject[] referencedJavaProjects, boolean debuggable) {
FileOutputStream fos = null;
try {
@@ -1083,6 +1086,18 @@ public class ApkBuilder extends BaseBuilder {
writeNativeLibraries((IFolder) libFolder, builder, debuggable);
}
+ // write the native libraries for the library projects.
+ if (libProjects != null) {
+ for (IProject lib : libProjects) {
+ libFolder = lib.findMember(SdkConstants.FD_NATIVE_LIBS);
+ if (libFolder != null && libFolder.exists() &&
+ libFolder.getType() == IResource.FOLDER) {
+ // look inside and put .so in lib/* by keeping the relative folder path.
+ writeNativeLibraries((IFolder) libFolder, builder, debuggable);
+ }
+ }
+ }
+
// close the jar file and write the manifest and sign it.
builder.close();
} catch (GeneralSecurityException e1) {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/LibraryDeltaVisitor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/LibraryDeltaVisitor.java
index a24eff0..77d7422 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/LibraryDeltaVisitor.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/LibraryDeltaVisitor.java
@@ -26,18 +26,23 @@ import org.eclipse.core.runtime.IPath;
/**
* Delta visitor specifically for Library resources.
- * The goal is to detect library resource change when compiling the main project
+ * The goal is to detect library resource/library changes when compiling the main project
* and trigger a resource recompilation/repackaging.
*
*/
public class LibraryDeltaVisitor implements IResourceDeltaVisitor {
private boolean mResChange = false;
+ private boolean mLibChange = false;
public boolean getResChange() {
return mResChange;
}
+ public boolean getLibChange() {
+ return mLibChange;
+ }
+
public boolean visit(IResourceDelta delta) throws CoreException {
// we are only going to look for changes in res/
// Since the delta visitor goes through the main
@@ -60,6 +65,10 @@ public class LibraryDeltaVisitor implements IResourceDeltaVisitor {
// res folder was changed!
// This is all that matters, we can stop (return false below)
mResChange = true;
+ } else if (SdkConstants.FD_NATIVE_LIBS.equalsIgnoreCase(segments[1])) {
+ // libs folder was changed.
+ // This is all that matters, we can stop (return false below)
+ mLibChange = true;
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ResourceManagerBuilder.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ResourceManagerBuilder.java
index 1aeb19f..fe6ac8a 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ResourceManagerBuilder.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/build/ResourceManagerBuilder.java
@@ -198,7 +198,9 @@ public class ResourceManagerBuilder extends BaseBuilder {
javaProject.setRawClasspath(entries, new SubProgressMonitor(monitor, 10));
}
- // refresh the whole project
+ // refresh sepcifcally the gen folder first, as it may break the build
+ // if it doesn't arrive in time then refresh the whole project as usual.
+ genFolder.refreshLocal(IResource.DEPTH_ZERO, new SubProgressMonitor(monitor, 10));
project.refreshLocal(IResource.DEPTH_INFINITE, new SubProgressMonitor(monitor, 10));
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidEditor.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidEditor.java
index 0a48284..c2b1b28 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidEditor.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/AndroidEditor.java
@@ -164,6 +164,15 @@ public abstract class AndroidEditor extends FormEditor implements IResourceChang
abstract protected void createFormPages();
/**
+ * Called by the base class {@link AndroidEditor} once all pages (custom form pages
+ * as well as text editor page) have been created. This give a chance to deriving
+ * classes to adjust behavior once the text page has been created.
+ */
+ protected void postCreatePages() {
+ // Nothing in the base class.
+ }
+
+ /**
* Creates the initial UI Root Node, including the known mandatory elements.
* @param force if true, a new UiManifestNode is recreated even if it already exists.
*/
@@ -199,8 +208,8 @@ public abstract class AndroidEditor extends FormEditor implements IResourceChang
mIsCreatingPage = true;
createFormPages();
createTextEditor();
-
createUndoRedoActions();
+ postCreatePages();
mIsCreatingPage = false;
}
@@ -305,6 +314,11 @@ public abstract class AndroidEditor extends FormEditor implements IResourceChang
protected void pageChange(int newPageIndex) {
super.pageChange(newPageIndex);
+ // Do not record page changes during creation of pages
+ if (mIsCreatingPage) {
+ return;
+ }
+
if (getEditorInput() instanceof IFileEditorInput) {
IFile file = ((IFileEditorInput) getEditorInput()).getFile();
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ExplodedRenderingHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ExplodedRenderingHelper.java
index 62d1b6c..be882a7 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ExplodedRenderingHelper.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/ExplodedRenderingHelper.java
@@ -84,7 +84,7 @@ public final class ExplodedRenderingHelper {
* @param root the root node (ie the top layout).
* @param layoutNames the list of layout classes
*/
- ExplodedRenderingHelper(Node root, Set<String> layoutNames) {
+ public ExplodedRenderingHelper(Node root, Set<String> layoutNames) {
mLayoutNames = layoutNames;
computePadding(root, mPadding);
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 c407ff9..c059a41 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
@@ -164,12 +164,14 @@ public class LayoutEditor extends AndroidEditor implements IShowEditorInput, IPa
input.toString());
}
- // It is possible that the Layout Editor alreadys exits if a different version
+ // It is possible that the Layout Editor already exits if a different version
// of the same layout is being opened (either through "open" action from
// the user, or through a configuration change in the configuration selector.)
if (mGraphicalEditor == null) {
- if (System.getenv("USE_GLE2") != null) { //$NON-NLS-1$ //$NON-NLS-2$
+ String useGle2 = System.getenv("USE_GLE2"); //$NON-NLS-1$
+
+ if (useGle2 != null && !useGle2.equals("0")) { //$NON-NLS-1$
mGraphicalEditor = new GraphicalEditorPart(this);
} else {
mGraphicalEditor = new GraphicalLayoutEditor(this);
@@ -196,6 +198,25 @@ public class LayoutEditor extends AndroidEditor implements IShowEditorInput, IPa
}
}
+ @Override
+ protected void postCreatePages() {
+ super.postCreatePages();
+
+ // This is called after the createFormPages() and createTextPage() methods have
+ // been called. Usually we select the first page (e.g. the GLE here) but right
+ // now we're going to temporarily select the last page (the XML text editor) if
+ // GLE1 is being used. That's because GLE1 is mostly useless and being deprecated.
+ //
+ // Note that this sets the default page. Eventually a default page might be
+ // restored by selectDefaultPage() later based on the last page used by the user.
+ //
+ // TODO revert this once GLE2 becomes useful and is the default.
+
+ if (mGraphicalEditor instanceof GraphicalLayoutEditor) {
+ setActivePage(getPageCount() - 1);
+ }
+ }
+
/* (non-java doc)
* Change the tab/title name to include the name of the layout.
*/
@@ -353,8 +374,14 @@ public class LayoutEditor extends AndroidEditor implements IShowEditorInput, IPa
}
public void partOpened(IWorkbenchPart part) {
- EclipseUiHelper.showView(EclipseUiHelper.CONTENT_OUTLINE_VIEW_ID, false /* activate */);
- EclipseUiHelper.showView(EclipseUiHelper.PROPERTY_SHEET_VIEW_ID, false /* activate */);
+ /*
+ * We used to automatically bring the outline and the property sheet to view
+ * when opening the editor. This behavior has always been a mixed bag and not
+ * exactly satisfactory. GLE1 is being useless/deprecated and GLE2 will need to
+ * improve on that, so right now let's comment this out.
+ */
+ //EclipseUiHelper.showView(EclipseUiHelper.CONTENT_OUTLINE_VIEW_ID, false /* activate */);
+ //EclipseUiHelper.showView(EclipseUiHelper.PROPERTY_SHEET_VIEW_ID, false /* activate */);
}
public class UiEditorActions extends UiActions {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationComposite.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationComposite.java
index f3bf078..6b648e2 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationComposite.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/configuration/ConfigurationComposite.java
@@ -213,11 +213,13 @@ public class ConfigurationComposite extends Composite {
locale = new ResourceQualifier[2];
String locales[] = values[2].split(SEP_LOCALE);
- if (locales[0].length() > 0) {
- locale[0] = new LanguageQualifier(locales[0]);
- }
- if (locales[1].length() > 0) {
- locale[1] = new RegionQualifier(locales[1]);
+ if (locales.length >= 2) {
+ if (locales[0].length() > 0) {
+ locale[0] = new LanguageQualifier(locales[0]);
+ }
+ if (locales[1].length() > 0) {
+ locale[1] = new RegionQualifier(locales[1]);
+ }
}
theme = values[3];
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/pages/OverviewExportPart.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/pages/OverviewExportPart.java
index ec947c5..4c75a86 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/pages/OverviewExportPart.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/manifest/pages/OverviewExportPart.java
@@ -19,6 +19,8 @@ package com.android.ide.eclipse.adt.internal.editors.manifest.pages;
import com.android.ide.eclipse.adt.internal.editors.manifest.ManifestEditor;
import com.android.ide.eclipse.adt.internal.editors.ui.SectionHelper.ManifestSectionPart;
import com.android.ide.eclipse.adt.internal.project.ExportHelper;
+import com.android.ide.eclipse.adt.internal.project.ProjectState;
+import com.android.ide.eclipse.adt.internal.sdk.Sdk;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
@@ -43,45 +45,69 @@ final class OverviewExportPart extends ManifestSectionPart {
mOverviewPage = overviewPage;
Section section = getSection();
section.setText("Exporting");
- section.setDescription("To export the application for distribution, you have the following options:");
- Composite table = createTableLayout(toolkit, 2 /* numColumns */);
-
- StringBuffer buf = new StringBuffer();
- buf.append("<form><li><a href=\"wizard\">"); //$NON-NLS-1$
- buf.append("Use the Export Wizard");
- buf.append("</a>"); //$NON-NLS-1$
- buf.append(" to export and sign an APK");
- buf.append("</li>"); //$NON-NLS-1$
- buf.append("<li><a href=\"manual\">"); //$NON-NLS-1$
- buf.append("Export an unsigned APK");
- buf.append("</a>"); //$NON-NLS-1$
- buf.append(" and sign it manually");
- buf.append("</li></form>"); //$NON-NLS-1$
+ final IProject project = getProject();
+ boolean isLibrary = false;
+ if (project != null) {
+ ProjectState state = Sdk.getProjectState(project);
+ if (state != null) {
+ isLibrary = state.isLibrary();
+ }
+ }
+
+ if (isLibrary) {
+ section.setDescription("Library project cannot be exported.");
+ Composite table = createTableLayout(toolkit, 2 /* numColumns */);
+ createFormText(table, toolkit, true, "<form></form>", false /* setupLayoutData */);
+ } else {
+ section.setDescription("To export the application for distribution, you have the following options:");
+
+ Composite table = createTableLayout(toolkit, 2 /* numColumns */);
+
+ StringBuffer buf = new StringBuffer();
+ buf.append("<form><li><a href=\"wizard\">"); //$NON-NLS-1$
+ buf.append("Use the Export Wizard");
+ buf.append("</a>"); //$NON-NLS-1$
+ buf.append(" to export and sign an APK");
+ buf.append("</li>"); //$NON-NLS-1$
+ buf.append("<li><a href=\"manual\">"); //$NON-NLS-1$
+ buf.append("Export an unsigned APK");
+ buf.append("</a>"); //$NON-NLS-1$
+ buf.append(" and sign it manually");
+ buf.append("</li></form>"); //$NON-NLS-1$
- FormText text = createFormText(table, toolkit, true, buf.toString(),
- false /* setupLayoutData */);
- text.addHyperlinkListener(new HyperlinkAdapter() {
- @Override
- public void linkActivated(HyperlinkEvent e) {
- // get the project from the editor
- IEditorInput input = mOverviewPage.mEditor.getEditorInput();
- if (input instanceof FileEditorInput) {
- FileEditorInput fileInput = (FileEditorInput)input;
- IFile file = fileInput.getFile();
- IProject project = file.getProject();
-
- if ("manual".equals(e.data)) { //$NON-NLS-1$
- // now we can export an unsigned apk for the project.
- ExportHelper.exportProject(project);
- } else {
- // call the export wizard
- ExportHelper.startExportWizard(project);
+ FormText text = createFormText(table, toolkit, true, buf.toString(),
+ false /* setupLayoutData */);
+ text.addHyperlinkListener(new HyperlinkAdapter() {
+ @Override
+ public void linkActivated(HyperlinkEvent e) {
+ if (project != null) {
+ if ("manual".equals(e.data)) { //$NON-NLS-1$
+ // now we can export an unsigned apk for the project.
+ ExportHelper.exportProject(project);
+ } else {
+ // call the export wizard
+ ExportHelper.startExportWizard(project);
+ }
}
}
- }
- });
-
+ });
+ }
+
layoutChanged();
- }
+ }
+
+ /**
+ * Returns the project of the edited file.
+ */
+ private IProject getProject() {
+ IEditorInput input = mOverviewPage.mEditor.getEditorInput();
+ if (input instanceof FileEditorInput) {
+ FileEditorInput fileInput = (FileEditorInput)input;
+ IFile file = fileInput.getFile();
+ return file.getProject();
+ }
+
+ return null;
+ }
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/LaunchMessages.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/LaunchMessages.java
index c105215..d09ddff 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/LaunchMessages.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/LaunchMessages.java
@@ -42,6 +42,8 @@ public class LaunchMessages extends NLS {
public static String InstrValidator_WrongRunnerTypeMsg_s;
public static String RemoteAdtTestRunner_RunCompleteMsg;
public static String RemoteAdtTestRunner_RunFailedMsg_s;
+
+ public static String RemoteAdtTestRunner_RunIOException_s;
public static String RemoteAdtTestRunner_RunStoppedMsg;
static {
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/LaunchShortcut.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/LaunchShortcut.java
index 1235f9d..432827e 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/LaunchShortcut.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/LaunchShortcut.java
@@ -16,15 +16,20 @@
package com.android.ide.eclipse.adt.internal.launch;
+import com.android.ide.eclipse.adt.internal.project.ProjectState;
+import com.android.ide.eclipse.adt.internal.sdk.Sdk;
+
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.debug.ui.ILaunchShortcut;
+import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.PlatformUI;
/**
* Launch shortcut to launch debug/run configuration directly.
@@ -52,8 +57,17 @@ public class LaunchShortcut implements ILaunchShortcut {
IProject project = r.getProject();
if (project != null) {
- // and launch
- launch(project, mode);
+ ProjectState state = Sdk.getProjectState(project);
+ if (state != null && state.isLibrary()) {
+
+ MessageDialog.openError(
+ PlatformUI.getWorkbench().getDisplay().getActiveShell(),
+ "Android Launch",
+ "Android library projects cannot be launched.");
+ } else{
+ // and launch
+ launch(project, mode);
+ }
}
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/MainLaunchConfigTab.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/MainLaunchConfigTab.java
index 2c96c98..1374dc7 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/MainLaunchConfigTab.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/MainLaunchConfigTab.java
@@ -289,7 +289,8 @@ public class MainLaunchConfigTab extends AbstractLaunchConfigurationTab {
*/
protected void handleProjectButtonSelected() {
IJavaProject javaProject = mProjectChooserHelper.chooseJavaProject(
- mProjText.getText().trim());
+ mProjText.getText().trim(),
+ "Please select a project to launch");
if (javaProject == null) {
return;
}// end if
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/junit/AndroidJUnitLaunchConfigurationTab.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/junit/AndroidJUnitLaunchConfigurationTab.java
index 0850e14..305e703 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/junit/AndroidJUnitLaunchConfigurationTab.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/junit/AndroidJUnitLaunchConfigurationTab.java
@@ -556,7 +556,8 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat
* constraining the search for main types to the specified project.
*/
private void handleProjectButtonSelected() {
- IJavaProject project = mProjectChooserHelper.chooseJavaProject(getProjectName());
+ IJavaProject project = mProjectChooserHelper.chooseJavaProject(getProjectName(),
+ "Please select a project to launch");
if (project == null) {
return;
}
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 af87254..0a045bc 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
@@ -27,6 +27,8 @@ import org.eclipse.jdt.internal.junit.runner.RemoteTestRunner;
import org.eclipse.jdt.internal.junit.runner.TestExecution;
import org.eclipse.jdt.internal.junit.runner.TestReferenceFailure;
+import java.io.IOException;
+
/**
* Supports Eclipse JUnit execution of Android tests.
* <p/>
@@ -98,24 +100,29 @@ public class RemoteAdtTestRunner extends RemoteTestRunner {
// set log only to first collect test case info, so Eclipse has correct test case count/
// tree info
runner.setLogOnly(true);
- TestCollector collector = new TestCollector();
- runner.run(collector);
- if (collector.getErrorMessage() != null) {
- // error occurred during test collection.
- reportError(collector.getErrorMessage());
- // abort here
- notifyTestRunEnded(0);
- return;
- }
- notifyTestRunStarted(collector.getTestCaseCount());
- collector.sendTrees(this);
-
- // now do real execution
- runner.setLogOnly(false);
- if (mLaunchInfo.isDebugMode()) {
- runner.setDebug(true);
+ TestCollector collector = new TestCollector();
+ try {
+ runner.run(collector);
+ if (collector.getErrorMessage() != null) {
+ // error occurred during test collection.
+ reportError(collector.getErrorMessage());
+ // abort here
+ notifyTestRunEnded(0);
+ return;
+ }
+ notifyTestRunStarted(collector.getTestCaseCount());
+ collector.sendTrees(this);
+
+ // now do real execution
+ runner.setLogOnly(false);
+ if (mLaunchInfo.isDebugMode()) {
+ runner.setDebug(true);
+ }
+ runner.run(new TestRunListener());
+ } catch (IOException e) {
+ reportError(String.format(LaunchMessages.RemoteAdtTestRunner_RunIOException_s,
+ e.getMessage()));
}
- runner.run(new TestRunListener());
}
/**
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/messages.properties b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/messages.properties
index 756aa61..67c9116 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/messages.properties
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/launch/messages.properties
@@ -35,4 +35,5 @@ InstrValidator_NoTestLibMsg_s=The application does not declare uses-library %1$s
InstrValidator_WrongRunnerTypeMsg_s=The instrumentation runner must be of type %1$s
RemoteAdtTestRunner_RunCompleteMsg=Test run complete
RemoteAdtTestRunner_RunFailedMsg_s=Test run failed: %1$s
+RemoteAdtTestRunner_RunIOException_s=Test run failed. Lost connection with device: %s
RemoteAdtTestRunner_RunStoppedMsg=Test run stopped
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ProjectChooserHelper.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ProjectChooserHelper.java
index e549d58..a7a6e72 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ProjectChooserHelper.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ProjectChooserHelper.java
@@ -104,15 +104,20 @@ public class ProjectChooserHelper {
*
* @param projectName If non null and not empty, represents the name of an Android project
* that will be selected by default.
+ * @param message Message for the dialog box. Can be null in which case a default message
+ * is displayed.
* @return the project chosen by the user in the dialog, or null if the dialog was canceled.
*/
- public IJavaProject chooseJavaProject(String projectName) {
+ public IJavaProject chooseJavaProject(String projectName, String message) {
ILabelProvider labelProvider = new JavaElementLabelProvider(
JavaElementLabelProvider.SHOW_DEFAULT);
ElementListSelectionDialog dialog = new ElementListSelectionDialog(
mParentShell, labelProvider);
dialog.setTitle("Project Selection");
- dialog.setMessage("Select a project to constrain your search.");
+ if (message == null) {
+ message = "Please select a project";
+ }
+ dialog.setMessage(message);
IWorkspaceRoot workspaceRoot = ResourcesPlugin.getWorkspace().getRoot();
IJavaModel javaModel = JavaCore.create(workspaceRoot);
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ProjectState.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ProjectState.java
index 8c08baf..2a55f74 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ProjectState.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/project/ProjectState.java
@@ -359,7 +359,8 @@ public final class ProjectState {
public LibraryState getLibrary(IProject library) {
synchronized (mLibraries) {
for (LibraryState state : mLibraries) {
- if (state.getProjectState().equals(library)) {
+ ProjectState ps = state.getProjectState();
+ if (ps != null && ps.equals(library)) {
return state;
}
}
@@ -371,7 +372,8 @@ public final class ProjectState {
public LibraryState getLibrary(String name) {
synchronized (mLibraries) {
for (LibraryState state : mLibraries) {
- if (state.getProjectState().getProject().getName().equals(name)) {
+ ProjectState ps = state.getProjectState();
+ if (ps != null && ps.getProject().getName().equals(name)) {
return state;
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/properties/LibraryProperties.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/properties/LibraryProperties.java
index 6bcc0d3..1675f7f 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/properties/LibraryProperties.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/properties/LibraryProperties.java
@@ -154,7 +154,8 @@ final class LibraryProperties {
mAddButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
- IJavaProject javaProject = mProjectChooser.chooseJavaProject(null);
+ IJavaProject javaProject = mProjectChooser.chooseJavaProject(null /*projectName*/,
+ "Please select a library project");
if (javaProject != null) {
IProject iProject = javaProject.getProject();
IPath relativePath = Sdk.makeRelativeTo(
@@ -179,6 +180,7 @@ final class LibraryProperties {
mItemDataList.remove(data);
mTable.remove(mTable.getSelectionIndex());
resetEnabled();
+ mMustSave = true;
}
});
@@ -201,6 +203,7 @@ final class LibraryProperties {
// reset the selection
mTable.select(index - 1);
resetEnabled();
+ mMustSave = true;
}
});
@@ -220,6 +223,7 @@ final class LibraryProperties {
// reset the selection
mTable.select(index + 1);
resetEnabled();
+ mMustSave = true;
}
});
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/actions/ExportAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/actions/ExportAction.java
index 9093470..c331680 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/actions/ExportAction.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/actions/ExportAction.java
@@ -17,23 +17,29 @@
package com.android.ide.eclipse.adt.internal.wizards.actions;
import com.android.ide.eclipse.adt.internal.project.ExportHelper;
+import com.android.ide.eclipse.adt.internal.project.ProjectState;
+import com.android.ide.eclipse.adt.internal.sdk.Sdk;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IObjectActionDelegate;
import org.eclipse.ui.IWorkbenchPart;
public class ExportAction implements IObjectActionDelegate {
private ISelection mSelection;
+ private Shell mShell;
/**
* @see IObjectActionDelegate#setActivePart(IAction, IWorkbenchPart)
*/
public void setActivePart(IAction action, IWorkbenchPart targetPart) {
+ mShell = targetPart.getSite().getShell();
}
public void run(IAction action) {
@@ -53,13 +59,19 @@ public class ExportAction implements IObjectActionDelegate {
// and finally do the action
if (project != null) {
- ExportHelper.exportProject(project);
+ ProjectState state = Sdk.getProjectState(project);
+ if (state.isLibrary()) {
+ MessageDialog.openError(mShell, "Android Export",
+ "Android library projects cannot be exported.");
+ } else {
+ ExportHelper.exportProject(project);
+ }
}
}
}
}
public void selectionChanged(IAction action, ISelection selection) {
- this.mSelection = selection;
+ mSelection = selection;
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/actions/ExportWizardAction.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/actions/ExportWizardAction.java
index 8165f97..cfdab0f 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/actions/ExportWizardAction.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/actions/ExportWizardAction.java
@@ -16,9 +16,14 @@
package com.android.ide.eclipse.adt.internal.wizards.actions;
+import com.android.ide.eclipse.adt.internal.project.ProjectState;
+import com.android.ide.eclipse.adt.internal.sdk.Sdk;
import com.android.ide.eclipse.adt.internal.wizards.export.ExportWizard;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.wizard.WizardDialog;
@@ -42,16 +47,39 @@ public class ExportWizardAction implements IObjectActionDelegate {
if (mSelection instanceof IStructuredSelection) {
IStructuredSelection selection = (IStructuredSelection)mSelection;
- // call the export wizard on the current selection.
- ExportWizard wizard = new ExportWizard();
- wizard.init(mWorkbench, selection);
- WizardDialog dialog = new WizardDialog(mWorkbench.getDisplay().getActiveShell(),
- wizard);
- dialog.open();
+ // get the unique selected item.
+ if (selection.size() == 1) {
+ Object element = selection.getFirstElement();
+
+ // get the project object from it.
+ IProject project = null;
+ if (element instanceof IProject) {
+ project = (IProject) element;
+ } else if (element instanceof IAdaptable) {
+ project = (IProject) ((IAdaptable) element).getAdapter(IProject.class);
+ }
+
+ // and finally do the action
+ if (project != null) {
+ ProjectState state = Sdk.getProjectState(project);
+ if (state.isLibrary()) {
+ MessageDialog.openError(mWorkbench.getDisplay().getActiveShell(),
+ "Android Export",
+ "Android library projects cannot be exported.");
+ } else {
+ // call the export wizard on the current selection.
+ ExportWizard wizard = new ExportWizard();
+ wizard.init(mWorkbench, selection);
+ WizardDialog dialog = new WizardDialog(
+ mWorkbench.getDisplay().getActiveShell(), wizard);
+ dialog.open();
+ }
+ }
+ }
}
}
public void selectionChanged(IAction action, ISelection selection) {
- this.mSelection = selection;
+ mSelection = selection;
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/ProjectCheckPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/ProjectCheckPage.java
index 11a40e5..aa65e6e 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/ProjectCheckPage.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/export/ProjectCheckPage.java
@@ -109,7 +109,8 @@ final class ProjectCheckPage extends ExportWizardPage {
@Override
public void widgetSelected(SelectionEvent e) {
IJavaProject javaProject = mProjectChooserHelper.chooseJavaProject(
- mProjectText.getText().trim());
+ mProjectText.getText().trim(),
+ "Please select a project to export");
if (javaProject != null) {
IProject project = javaProject.getProject();
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectWizard.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectWizard.java
index 2d51f89..517ffa0 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectWizard.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewProjectWizard.java
@@ -39,6 +39,7 @@ import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.SubProgressMonitor;
@@ -513,6 +514,9 @@ public class NewProjectWizard extends Wizard implements INewWizard {
try {
getContainer().run(true /* fork */, true /* cancelable */, op);
} catch (InvocationTargetException e) {
+
+ AdtPlugin.log(e, "New Project Wizard failed");
+
// The runnable threw an exception
Throwable t = e.getTargetException();
if (t instanceof CoreException) {
@@ -522,11 +526,20 @@ public class NewProjectWizard extends Wizard implements INewWizard {
// and there's a resource with a similar name.
MessageDialog.openError(getShell(), "Error", "Error: Case Variant Exists");
} else {
- ErrorDialog.openError(getShell(), "Error", null, core.getStatus());
+ ErrorDialog.openError(getShell(), "Error", core.getMessage(), core.getStatus());
}
} else {
// Some other kind of exception
- MessageDialog.openError(getShell(), "Error", t.getMessage());
+ String msg = t.getMessage();
+ Throwable t1 = t;
+ while (msg == null && t1.getCause() != null) {
+ msg = t1.getMessage();
+ t1 = t1.getCause();
+ }
+ if (msg == null) {
+ msg = t.toString();
+ }
+ MessageDialog.openError(getShell(), "Error", msg);
}
e.printStackTrace();
} catch (InterruptedException e) {
@@ -747,6 +760,15 @@ public class NewProjectWizard extends Wizard implements INewWizard {
// Replace all keyword parameters
manifestTemplate = replaceParameters(manifestTemplate, parameters);
+ if (manifestTemplate == null) {
+ // Inform the user there will be not manifest.
+ AdtPlugin.logAndPrintError(null, getWindowTitle() /*TAG*/,
+ "Failed to generate the Android manifest. Missing template %s",
+ TEMPLATE_MANIFEST);
+ // Abort now, there's no need to continue
+ return;
+ }
+
if (parameters.containsKey(PARAM_ACTIVITY)) {
// now get the activity template
String activityTemplate = AdtPlugin.readEmbeddedTextFile(TEMPLATE_ACTIVITIES);
@@ -757,11 +779,15 @@ public class NewProjectWizard extends Wizard implements INewWizard {
// set the intent.
String intent = AdtPlugin.readEmbeddedTextFile(TEMPLATE_INTENT_LAUNCHER);
- // set the intent to the main activity
- activities = activities.replaceAll(PH_INTENT_FILTERS, intent);
+ if (activities != null) {
+ if (intent != null) {
+ // set the intent to the main activity
+ activities = activities.replaceAll(PH_INTENT_FILTERS, intent);
+ }
- // set the activity(ies) in the manifest
- manifestTemplate = manifestTemplate.replaceAll(PH_ACTIVITIES, activities);
+ // set the activity(ies) in the manifest
+ manifestTemplate = manifestTemplate.replaceAll(PH_ACTIVITIES, activities);
+ }
} else {
// remove the activity(ies) from the manifest
manifestTemplate = manifestTemplate.replaceAll(PH_ACTIVITIES, ""); //$NON-NLS-1$
@@ -771,11 +797,17 @@ public class NewProjectWizard extends Wizard implements INewWizard {
if (parameters.containsKey(PARAM_TEST_TARGET_PACKAGE)) {
// Set the uses-library needed by the test project
String usesLibrary = AdtPlugin.readEmbeddedTextFile(TEMPLATE_TEST_USES_LIBRARY);
- manifestTemplate = manifestTemplate.replaceAll(PH_TEST_USES_LIBRARY, usesLibrary);
+ if (usesLibrary != null) {
+ manifestTemplate = manifestTemplate.replaceAll(
+ PH_TEST_USES_LIBRARY, usesLibrary);
+ }
// Set the instrumentation element needed by the test project
String instru = AdtPlugin.readEmbeddedTextFile(TEMPLATE_TEST_INSTRUMENTATION);
- manifestTemplate = manifestTemplate.replaceAll(PH_TEST_INSTRUMENTATION, instru);
+ if (instru != null) {
+ manifestTemplate = manifestTemplate.replaceAll(
+ PH_TEST_INSTRUMENTATION, instru);
+ }
// Replace PARAM_TEST_TARGET_PACKAGE itself now
manifestTemplate = replaceParameters(manifestTemplate, parameters);
@@ -789,8 +821,10 @@ public class NewProjectWizard extends Wizard implements INewWizard {
String minSdkVersion = (String) parameters.get(PARAM_MIN_SDK_VERSION);
if (minSdkVersion != null && minSdkVersion.length() > 0) {
String usesSdkTemplate = AdtPlugin.readEmbeddedTextFile(TEMPLATE_USES_SDK);
- String usesSdk = replaceParameters(usesSdkTemplate, parameters);
- manifestTemplate = manifestTemplate.replaceAll(PH_USES_SDK, usesSdk);
+ if (usesSdkTemplate != null) {
+ String usesSdk = replaceParameters(usesSdkTemplate, parameters);
+ manifestTemplate = manifestTemplate.replaceAll(PH_USES_SDK, usesSdk);
+ }
} else {
manifestTemplate = manifestTemplate.replaceAll(PH_USES_SDK, "");
}
@@ -1083,9 +1117,28 @@ public class NewProjectWizard extends Wizard implements INewWizard {
* @return A new String object with the placeholder replaced by the values.
*/
private String replaceParameters(String str, Map<String, Object> parameters) {
+
+ if (parameters == null) {
+ AdtPlugin.log(IStatus.ERROR,
+ "NPW replace parameters: null parameter map. String: '%s'", str); //$NON-NLS-1$
+ return str;
+ } else if (str == null) {
+ AdtPlugin.log(IStatus.ERROR,
+ "NPW replace parameters: null template string"); //$NON-NLS-1$
+ return str;
+ }
+
for (Entry<String, Object> entry : parameters.entrySet()) {
- if (entry.getValue() instanceof String) {
- str = str.replaceAll(entry.getKey(), (String) entry.getValue());
+ if (entry != null && entry.getValue() instanceof String) {
+ Object value = entry.getValue();
+ if (value == null) {
+ AdtPlugin.log(IStatus.ERROR,
+ "NPW replace parameters: null value for key '%s' in template '%s'", //$NON-NLS-1$
+ entry.getKey(),
+ str);
+ } else {
+ str = str.replaceAll(entry.getKey(), (String) value);
+ }
}
}
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewTestProjectCreationPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewTestProjectCreationPage.java
index d43831e..df5a39b 100755
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewTestProjectCreationPage.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newproject/NewTestProjectCreationPage.java
@@ -812,7 +812,8 @@ public class NewTestProjectCreationPage extends WizardPage {
* Callback called when the user uses the "Browse Projects" button.
*/
private void onProjectBrowse() {
- IJavaProject p = mProjectChooserHelper.chooseJavaProject(mTestedProjectNameField.getText());
+ IJavaProject p = mProjectChooserHelper.chooseJavaProject(mTestedProjectNameField.getText(),
+ null /*message*/);
if (p != null) {
setExistingProject(p.getProject());
mTestedProjectNameField.setText(mExistingTestedProject.getName());
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java
index dc4d852..81a9952 100644
--- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/wizards/newxmlfile/NewXmlFileCreationPage.java
@@ -875,7 +875,8 @@ class NewXmlFileCreationPage extends WizardPage {
* Callback called when the user uses the "Browse Projects" button.
*/
private void onProjectBrowse() {
- IJavaProject p = mProjectChooserHelper.chooseJavaProject(mProjectTextField.getText());
+ IJavaProject p = mProjectChooserHelper.chooseJavaProject(mProjectTextField.getText(),
+ "Please select the target project");
if (p != null) {
changeProject(p.getProject());
mProjectTextField.setText(mProject.getName());
diff --git a/eclipse/plugins/com.android.ide.eclipse.ddms/META-INF/MANIFEST.MF b/eclipse/plugins/com.android.ide.eclipse.ddms/META-INF/MANIFEST.MF
index 1ddabe1..1dad84f 100644
--- a/eclipse/plugins/com.android.ide.eclipse.ddms/META-INF/MANIFEST.MF
+++ b/eclipse/plugins/com.android.ide.eclipse.ddms/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Dalvik Debug Monitor Service
Bundle-SymbolicName: com.android.ide.eclipse.ddms;singleton:=true
-Bundle-Version: 0.9.7.qualifier
+Bundle-Version: 0.9.8.qualifier
Bundle-Activator: com.android.ide.eclipse.ddms.DdmsPlugin
Bundle-Vendor: The Android Open Source Project
Bundle-Localization: plugin
diff --git a/eclipse/plugins/com.android.ide.eclipse.tests/META-INF/MANIFEST.MF b/eclipse/plugins/com.android.ide.eclipse.tests/META-INF/MANIFEST.MF
index 5af8623..9bd7db8 100644
--- a/eclipse/plugins/com.android.ide.eclipse.tests/META-INF/MANIFEST.MF
+++ b/eclipse/plugins/com.android.ide.eclipse.tests/META-INF/MANIFEST.MF
@@ -2,7 +2,7 @@ Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Android Plugin Tests
Bundle-SymbolicName: com.android.ide.eclipse.tests
-Bundle-Version: 0.9.7.qualifier
+Bundle-Version: 0.9.8.qualifier
Bundle-Activator: com.android.ide.eclipse.tests.AndroidTestPlugin
Require-Bundle: org.eclipse.ui,
org.eclipse.core.runtime,
diff --git a/eclipse/sites/external/site.xml b/eclipse/sites/external/site.xml
index 4e5f434..fc15b3a 100644
--- a/eclipse/sites/external/site.xml
+++ b/eclipse/sites/external/site.xml
@@ -3,10 +3,10 @@
<description url="https://dl-ssl.google.com/android/eclipse/">
Update Site for Android Development Toolkit
</description>
- <feature url="features/com.android.ide.eclipse.adt_0.9.7.qualifier.jar" id="com.android.ide.eclipse.adt" version="0.9.7.qualifier">
+ <feature url="features/com.android.ide.eclipse.adt_0.9.8.qualifier.jar" id="com.android.ide.eclipse.adt" version="0.9.8.qualifier">
<category name="developer"/>
</feature>
- <feature url="features/com.android.ide.eclipse.ddms_0.9.7.qualifier.jar" id="com.android.ide.eclipse.ddms" version="0.9.7.qualifier">
+ <feature url="features/com.android.ide.eclipse.ddms_0.9.8.qualifier.jar" id="com.android.ide.eclipse.ddms" version="0.9.8.qualifier">
<category name="developer"/>
</feature>
<category-def name="developer" label="Developer Tools">
diff --git a/eclipse/sites/internal/site.xml b/eclipse/sites/internal/site.xml
index da86a75..df2e13b 100644
--- a/eclipse/sites/internal/site.xml
+++ b/eclipse/sites/internal/site.xml
@@ -3,13 +3,13 @@
<description url="https://android.corp.google.com/adt/">
Update Site for Android Development Toolkit
</description>
- <feature url="features/com.android.ide.eclipse.adt_0.9.7.qualifier.jar" id="com.android.ide.eclipse.adt" version="0.9.7.qualifier">
+ <feature url="features/com.android.ide.eclipse.adt_0.9.8.qualifier.jar" id="com.android.ide.eclipse.adt" version="0.9.8.qualifier">
<category name="developer"/>
</feature>
- <feature url="features/com.android.ide.eclipse.ddms_0.9.7.qualifier.jar" id="com.android.ide.eclipse.ddms" version="0.9.7.qualifier">
+ <feature url="features/com.android.ide.eclipse.ddms_0.9.8.qualifier.jar" id="com.android.ide.eclipse.ddms" version="0.9.8.qualifier">
<category name="developer"/>
</feature>
- <feature url="features/com.android.ide.eclipse.tests_0.9.7.qualifier.jar" id="com.android.ide.eclipse.tests" version="0.9.7.qualifier">
+ <feature url="features/com.android.ide.eclipse.tests_0.9.8.qualifier.jar" id="com.android.ide.eclipse.tests" version="0.9.8.qualifier">
<category name="test"/>
</feature>
<category-def name="developer" label="Application Developer Tools">
diff --git a/emulator/gps/Android.mk b/emulator/gps/Android.mk
new file mode 100644
index 0000000..77b2de5
--- /dev/null
+++ b/emulator/gps/Android.mk
@@ -0,0 +1,30 @@
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+LOCAL_PATH := $(call my-dir)
+
+ifneq ($(TARGET_PRODUCT),sim)
+# HAL module implemenation, not prelinked and stored in
+# hw/<GPS_HARDWARE_MODULE_ID>.<ro.hardware>.so
+include $(CLEAR_VARS)
+LOCAL_PRELINK_MODULE := false
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+LOCAL_CFLAGS += -DQEMU_HARDWARE
+LOCAL_SHARED_LIBRARIES := liblog libcutils libhardware
+LOCAL_SRC_FILES := gps_qemu.c
+LOCAL_MODULE := gps.goldfish
+LOCAL_MODULE_TAGS := debug
+include $(BUILD_SHARED_LIBRARY)
+endif
diff --git a/emulator/gps/gps_qemu.c b/emulator/gps/gps_qemu.c
new file mode 100644
index 0000000..ce14fcb
--- /dev/null
+++ b/emulator/gps/gps_qemu.c
@@ -0,0 +1,941 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* this implements a GPS hardware library for the Android emulator.
+ * the following code should be built as a shared library that will be
+ * placed into /system/lib/hw/gps.goldfish.so
+ *
+ * it will be loaded by the code in hardware/libhardware/hardware.c
+ * which is itself called from android_location_GpsLocationProvider.cpp
+ */
+
+
+#include <errno.h>
+#include <pthread.h>
+#include <fcntl.h>
+#include <sys/epoll.h>
+#include <math.h>
+#include <time.h>
+
+#define LOG_TAG "gps_qemu"
+#include <cutils/log.h>
+#include <cutils/sockets.h>
+#include <hardware/gps.h>
+#include <hardware/qemud.h>
+
+/* the name of the qemud-controlled socket */
+#define QEMU_CHANNEL_NAME "gps"
+
+#define GPS_DEBUG 0
+
+#if GPS_DEBUG
+# define D(...) LOGD(__VA_ARGS__)
+#else
+# define D(...) ((void)0)
+#endif
+
+/*****************************************************************/
+/*****************************************************************/
+/***** *****/
+/***** N M E A T O K E N I Z E R *****/
+/***** *****/
+/*****************************************************************/
+/*****************************************************************/
+
+typedef struct {
+ const char* p;
+ const char* end;
+} Token;
+
+#define MAX_NMEA_TOKENS 16
+
+typedef struct {
+ int count;
+ Token tokens[ MAX_NMEA_TOKENS ];
+} NmeaTokenizer;
+
+static int
+nmea_tokenizer_init( NmeaTokenizer* t, const char* p, const char* end )
+{
+ int count = 0;
+ char* q;
+
+ // the initial '$' is optional
+ if (p < end && p[0] == '$')
+ p += 1;
+
+ // remove trailing newline
+ if (end > p && end[-1] == '\n') {
+ end -= 1;
+ if (end > p && end[-1] == '\r')
+ end -= 1;
+ }
+
+ // get rid of checksum at the end of the sentecne
+ if (end >= p+3 && end[-3] == '*') {
+ end -= 3;
+ }
+
+ while (p < end) {
+ const char* q = p;
+
+ q = memchr(p, ',', end-p);
+ if (q == NULL)
+ q = end;
+
+ if (q > p) {
+ if (count < MAX_NMEA_TOKENS) {
+ t->tokens[count].p = p;
+ t->tokens[count].end = q;
+ count += 1;
+ }
+ }
+ if (q < end)
+ q += 1;
+
+ p = q;
+ }
+
+ t->count = count;
+ return count;
+}
+
+static Token
+nmea_tokenizer_get( NmeaTokenizer* t, int index )
+{
+ Token tok;
+ static const char* dummy = "";
+
+ if (index < 0 || index >= t->count) {
+ tok.p = tok.end = dummy;
+ } else
+ tok = t->tokens[index];
+
+ return tok;
+}
+
+
+static int
+str2int( const char* p, const char* end )
+{
+ int result = 0;
+ int len = end - p;
+
+ for ( ; len > 0; len--, p++ )
+ {
+ int c;
+
+ if (p >= end)
+ goto Fail;
+
+ c = *p - '0';
+ if ((unsigned)c >= 10)
+ goto Fail;
+
+ result = result*10 + c;
+ }
+ return result;
+
+Fail:
+ return -1;
+}
+
+static double
+str2float( const char* p, const char* end )
+{
+ int result = 0;
+ int len = end - p;
+ char temp[16];
+
+ if (len >= (int)sizeof(temp))
+ return 0.;
+
+ memcpy( temp, p, len );
+ temp[len] = 0;
+ return strtod( temp, NULL );
+}
+
+/*****************************************************************/
+/*****************************************************************/
+/***** *****/
+/***** N M E A P A R S E R *****/
+/***** *****/
+/*****************************************************************/
+/*****************************************************************/
+
+#define NMEA_MAX_SIZE 83
+
+typedef struct {
+ int pos;
+ int overflow;
+ int utc_year;
+ int utc_mon;
+ int utc_day;
+ int utc_diff;
+ GpsLocation fix;
+ gps_location_callback callback;
+ char in[ NMEA_MAX_SIZE+1 ];
+} NmeaReader;
+
+
+static void
+nmea_reader_update_utc_diff( NmeaReader* r )
+{
+ time_t now = time(NULL);
+ struct tm tm_local;
+ struct tm tm_utc;
+ long time_local, time_utc;
+
+ gmtime_r( &now, &tm_utc );
+ localtime_r( &now, &tm_local );
+
+ time_local = tm_local.tm_sec +
+ 60*(tm_local.tm_min +
+ 60*(tm_local.tm_hour +
+ 24*(tm_local.tm_yday +
+ 365*tm_local.tm_year)));
+
+ time_utc = tm_utc.tm_sec +
+ 60*(tm_utc.tm_min +
+ 60*(tm_utc.tm_hour +
+ 24*(tm_utc.tm_yday +
+ 365*tm_utc.tm_year)));
+
+ r->utc_diff = time_utc - time_local;
+}
+
+
+static void
+nmea_reader_init( NmeaReader* r )
+{
+ memset( r, 0, sizeof(*r) );
+
+ r->pos = 0;
+ r->overflow = 0;
+ r->utc_year = -1;
+ r->utc_mon = -1;
+ r->utc_day = -1;
+ r->callback = NULL;
+ r->fix.size = sizeof(r->fix);
+
+ nmea_reader_update_utc_diff( r );
+}
+
+
+static void
+nmea_reader_set_callback( NmeaReader* r, gps_location_callback cb )
+{
+ r->callback = cb;
+ if (cb != NULL && r->fix.flags != 0) {
+ D("%s: sending latest fix to new callback", __FUNCTION__);
+ r->callback( &r->fix );
+ r->fix.flags = 0;
+ }
+}
+
+
+static int
+nmea_reader_update_time( NmeaReader* r, Token tok )
+{
+ int hour, minute;
+ double seconds;
+ struct tm tm;
+ time_t fix_time;
+
+ if (tok.p + 6 > tok.end)
+ return -1;
+
+ if (r->utc_year < 0) {
+ // no date yet, get current one
+ time_t now = time(NULL);
+ gmtime_r( &now, &tm );
+ r->utc_year = tm.tm_year + 1900;
+ r->utc_mon = tm.tm_mon + 1;
+ r->utc_day = tm.tm_mday;
+ }
+
+ hour = str2int(tok.p, tok.p+2);
+ minute = str2int(tok.p+2, tok.p+4);
+ seconds = str2float(tok.p+4, tok.end);
+
+ tm.tm_hour = hour;
+ tm.tm_min = minute;
+ tm.tm_sec = (int) seconds;
+ tm.tm_year = r->utc_year - 1900;
+ tm.tm_mon = r->utc_mon - 1;
+ tm.tm_mday = r->utc_day;
+ tm.tm_isdst = -1;
+
+ fix_time = mktime( &tm ) + r->utc_diff;
+ r->fix.timestamp = (long long)fix_time * 1000;
+ return 0;
+}
+
+static int
+nmea_reader_update_date( NmeaReader* r, Token date, Token time )
+{
+ Token tok = date;
+ int day, mon, year;
+
+ if (tok.p + 6 != tok.end) {
+ D("date not properly formatted: '%.*s'", tok.end-tok.p, tok.p);
+ return -1;
+ }
+ day = str2int(tok.p, tok.p+2);
+ mon = str2int(tok.p+2, tok.p+4);
+ year = str2int(tok.p+4, tok.p+6) + 2000;
+
+ if ((day|mon|year) < 0) {
+ D("date not properly formatted: '%.*s'", tok.end-tok.p, tok.p);
+ return -1;
+ }
+
+ r->utc_year = year;
+ r->utc_mon = mon;
+ r->utc_day = day;
+
+ return nmea_reader_update_time( r, time );
+}
+
+
+static double
+convert_from_hhmm( Token tok )
+{
+ double val = str2float(tok.p, tok.end);
+ int degrees = (int)(floor(val) / 100);
+ double minutes = val - degrees*100.;
+ double dcoord = degrees + minutes / 60.0;
+ return dcoord;
+}
+
+
+static int
+nmea_reader_update_latlong( NmeaReader* r,
+ Token latitude,
+ char latitudeHemi,
+ Token longitude,
+ char longitudeHemi )
+{
+ double lat, lon;
+ Token tok;
+
+ tok = latitude;
+ if (tok.p + 6 > tok.end) {
+ D("latitude is too short: '%.*s'", tok.end-tok.p, tok.p);
+ return -1;
+ }
+ lat = convert_from_hhmm(tok);
+ if (latitudeHemi == 'S')
+ lat = -lat;
+
+ tok = longitude;
+ if (tok.p + 6 > tok.end) {
+ D("longitude is too short: '%.*s'", tok.end-tok.p, tok.p);
+ return -1;
+ }
+ lon = convert_from_hhmm(tok);
+ if (longitudeHemi == 'W')
+ lon = -lon;
+
+ r->fix.flags |= GPS_LOCATION_HAS_LAT_LONG;
+ r->fix.latitude = lat;
+ r->fix.longitude = lon;
+ return 0;
+}
+
+
+static int
+nmea_reader_update_altitude( NmeaReader* r,
+ Token altitude,
+ Token units )
+{
+ double alt;
+ Token tok = altitude;
+
+ if (tok.p >= tok.end)
+ return -1;
+
+ r->fix.flags |= GPS_LOCATION_HAS_ALTITUDE;
+ r->fix.altitude = str2float(tok.p, tok.end);
+ return 0;
+}
+
+
+static int
+nmea_reader_update_bearing( NmeaReader* r,
+ Token bearing )
+{
+ double alt;
+ Token tok = bearing;
+
+ if (tok.p >= tok.end)
+ return -1;
+
+ r->fix.flags |= GPS_LOCATION_HAS_BEARING;
+ r->fix.bearing = str2float(tok.p, tok.end);
+ return 0;
+}
+
+
+static int
+nmea_reader_update_speed( NmeaReader* r,
+ Token speed )
+{
+ double alt;
+ Token tok = speed;
+
+ if (tok.p >= tok.end)
+ return -1;
+
+ r->fix.flags |= GPS_LOCATION_HAS_SPEED;
+ r->fix.speed = str2float(tok.p, tok.end);
+ return 0;
+}
+
+
+static void
+nmea_reader_parse( NmeaReader* r )
+{
+ /* we received a complete sentence, now parse it to generate
+ * a new GPS fix...
+ */
+ NmeaTokenizer tzer[1];
+ Token tok;
+
+ D("Received: '%.*s'", r->pos, r->in);
+ if (r->pos < 9) {
+ D("Too short. discarded.");
+ return;
+ }
+
+ nmea_tokenizer_init(tzer, r->in, r->in + r->pos);
+#if GPS_DEBUG
+ {
+ int n;
+ D("Found %d tokens", tzer->count);
+ for (n = 0; n < tzer->count; n++) {
+ Token tok = nmea_tokenizer_get(tzer,n);
+ D("%2d: '%.*s'", n, tok.end-tok.p, tok.p);
+ }
+ }
+#endif
+
+ tok = nmea_tokenizer_get(tzer, 0);
+ if (tok.p + 5 > tok.end) {
+ D("sentence id '%.*s' too short, ignored.", tok.end-tok.p, tok.p);
+ return;
+ }
+
+ // ignore first two characters.
+ tok.p += 2;
+ if ( !memcmp(tok.p, "GGA", 3) ) {
+ // GPS fix
+ Token tok_time = nmea_tokenizer_get(tzer,1);
+ Token tok_latitude = nmea_tokenizer_get(tzer,2);
+ Token tok_latitudeHemi = nmea_tokenizer_get(tzer,3);
+ Token tok_longitude = nmea_tokenizer_get(tzer,4);
+ Token tok_longitudeHemi = nmea_tokenizer_get(tzer,5);
+ Token tok_altitude = nmea_tokenizer_get(tzer,9);
+ Token tok_altitudeUnits = nmea_tokenizer_get(tzer,10);
+
+ nmea_reader_update_time(r, tok_time);
+ nmea_reader_update_latlong(r, tok_latitude,
+ tok_latitudeHemi.p[0],
+ tok_longitude,
+ tok_longitudeHemi.p[0]);
+ nmea_reader_update_altitude(r, tok_altitude, tok_altitudeUnits);
+
+ } else if ( !memcmp(tok.p, "GSA", 3) ) {
+ // do something ?
+ } else if ( !memcmp(tok.p, "RMC", 3) ) {
+ Token tok_time = nmea_tokenizer_get(tzer,1);
+ Token tok_fixStatus = nmea_tokenizer_get(tzer,2);
+ Token tok_latitude = nmea_tokenizer_get(tzer,3);
+ Token tok_latitudeHemi = nmea_tokenizer_get(tzer,4);
+ Token tok_longitude = nmea_tokenizer_get(tzer,5);
+ Token tok_longitudeHemi = nmea_tokenizer_get(tzer,6);
+ Token tok_speed = nmea_tokenizer_get(tzer,7);
+ Token tok_bearing = nmea_tokenizer_get(tzer,8);
+ Token tok_date = nmea_tokenizer_get(tzer,9);
+
+ D("in RMC, fixStatus=%c", tok_fixStatus.p[0]);
+ if (tok_fixStatus.p[0] == 'A')
+ {
+ nmea_reader_update_date( r, tok_date, tok_time );
+
+ nmea_reader_update_latlong( r, tok_latitude,
+ tok_latitudeHemi.p[0],
+ tok_longitude,
+ tok_longitudeHemi.p[0] );
+
+ nmea_reader_update_bearing( r, tok_bearing );
+ nmea_reader_update_speed ( r, tok_speed );
+ }
+ } else {
+ tok.p -= 2;
+ D("unknown sentence '%.*s", tok.end-tok.p, tok.p);
+ }
+ if (r->fix.flags != 0) {
+#if GPS_DEBUG
+ char temp[256];
+ char* p = temp;
+ char* end = p + sizeof(temp);
+ struct tm utc;
+
+ p += snprintf( p, end-p, "sending fix" );
+ if (r->fix.flags & GPS_LOCATION_HAS_LAT_LONG) {
+ p += snprintf(p, end-p, " lat=%g lon=%g", r->fix.latitude, r->fix.longitude);
+ }
+ if (r->fix.flags & GPS_LOCATION_HAS_ALTITUDE) {
+ p += snprintf(p, end-p, " altitude=%g", r->fix.altitude);
+ }
+ if (r->fix.flags & GPS_LOCATION_HAS_SPEED) {
+ p += snprintf(p, end-p, " speed=%g", r->fix.speed);
+ }
+ if (r->fix.flags & GPS_LOCATION_HAS_BEARING) {
+ p += snprintf(p, end-p, " bearing=%g", r->fix.bearing);
+ }
+ if (r->fix.flags & GPS_LOCATION_HAS_ACCURACY) {
+ p += snprintf(p,end-p, " accuracy=%g", r->fix.accuracy);
+ }
+ gmtime_r( (time_t*) &r->fix.timestamp, &utc );
+ p += snprintf(p, end-p, " time=%s", asctime( &utc ) );
+ D(temp);
+#endif
+ if (r->callback) {
+ r->callback( &r->fix );
+ r->fix.flags = 0;
+ }
+ else {
+ D("no callback, keeping data until needed !");
+ }
+ }
+}
+
+
+static void
+nmea_reader_addc( NmeaReader* r, int c )
+{
+ if (r->overflow) {
+ r->overflow = (c != '\n');
+ return;
+ }
+
+ if (r->pos >= (int) sizeof(r->in)-1 ) {
+ r->overflow = 1;
+ r->pos = 0;
+ return;
+ }
+
+ r->in[r->pos] = (char)c;
+ r->pos += 1;
+
+ if (c == '\n') {
+ nmea_reader_parse( r );
+ r->pos = 0;
+ }
+}
+
+
+/*****************************************************************/
+/*****************************************************************/
+/***** *****/
+/***** C O N N E C T I O N S T A T E *****/
+/***** *****/
+/*****************************************************************/
+/*****************************************************************/
+
+/* commands sent to the gps thread */
+enum {
+ CMD_QUIT = 0,
+ CMD_START = 1,
+ CMD_STOP = 2
+};
+
+
+/* this is the state of our connection to the qemu_gpsd daemon */
+typedef struct {
+ int init;
+ int fd;
+ GpsCallbacks callbacks;
+ pthread_t thread;
+ int control[2];
+} GpsState;
+
+static GpsState _gps_state[1];
+
+
+static void
+gps_state_done( GpsState* s )
+{
+ // tell the thread to quit, and wait for it
+ char cmd = CMD_QUIT;
+ void* dummy;
+ write( s->control[0], &cmd, 1 );
+ pthread_join(s->thread, &dummy);
+
+ // close the control socket pair
+ close( s->control[0] ); s->control[0] = -1;
+ close( s->control[1] ); s->control[1] = -1;
+
+ // close connection to the QEMU GPS daemon
+ close( s->fd ); s->fd = -1;
+ s->init = 0;
+}
+
+
+static void
+gps_state_start( GpsState* s )
+{
+ char cmd = CMD_START;
+ int ret;
+
+ do { ret=write( s->control[0], &cmd, 1 ); }
+ while (ret < 0 && errno == EINTR);
+
+ if (ret != 1)
+ D("%s: could not send CMD_START command: ret=%d: %s",
+ __FUNCTION__, ret, strerror(errno));
+}
+
+
+static void
+gps_state_stop( GpsState* s )
+{
+ char cmd = CMD_STOP;
+ int ret;
+
+ do { ret=write( s->control[0], &cmd, 1 ); }
+ while (ret < 0 && errno == EINTR);
+
+ if (ret != 1)
+ D("%s: could not send CMD_STOP command: ret=%d: %s",
+ __FUNCTION__, ret, strerror(errno));
+}
+
+
+static int
+epoll_register( int epoll_fd, int fd )
+{
+ struct epoll_event ev;
+ int ret, flags;
+
+ /* important: make the fd non-blocking */
+ flags = fcntl(fd, F_GETFL);
+ fcntl(fd, F_SETFL, flags | O_NONBLOCK);
+
+ ev.events = EPOLLIN;
+ ev.data.fd = fd;
+ do {
+ ret = epoll_ctl( epoll_fd, EPOLL_CTL_ADD, fd, &ev );
+ } while (ret < 0 && errno == EINTR);
+ return ret;
+}
+
+
+static int
+epoll_deregister( int epoll_fd, int fd )
+{
+ int ret;
+ do {
+ ret = epoll_ctl( epoll_fd, EPOLL_CTL_DEL, fd, NULL );
+ } while (ret < 0 && errno == EINTR);
+ return ret;
+}
+
+/* this is the main thread, it waits for commands from gps_state_start/stop and,
+ * when started, messages from the QEMU GPS daemon. these are simple NMEA sentences
+ * that must be parsed to be converted into GPS fixes sent to the framework
+ */
+static void*
+gps_state_thread( void* arg )
+{
+ GpsState* state = (GpsState*) arg;
+ NmeaReader reader[1];
+ int epoll_fd = epoll_create(2);
+ int started = 0;
+ int gps_fd = state->fd;
+ int control_fd = state->control[1];
+
+ nmea_reader_init( reader );
+
+ // register control file descriptors for polling
+ epoll_register( epoll_fd, control_fd );
+ epoll_register( epoll_fd, gps_fd );
+
+ D("gps thread running");
+
+ // now loop
+ for (;;) {
+ struct epoll_event events[2];
+ int ne, nevents;
+
+ nevents = epoll_wait( epoll_fd, events, 2, -1 );
+ if (nevents < 0) {
+ if (errno != EINTR)
+ LOGE("epoll_wait() unexpected error: %s", strerror(errno));
+ continue;
+ }
+ D("gps thread received %d events", nevents);
+ for (ne = 0; ne < nevents; ne++) {
+ if ((events[ne].events & (EPOLLERR|EPOLLHUP)) != 0) {
+ LOGE("EPOLLERR or EPOLLHUP after epoll_wait() !?");
+ goto Exit;
+ }
+ if ((events[ne].events & EPOLLIN) != 0) {
+ int fd = events[ne].data.fd;
+
+ if (fd == control_fd)
+ {
+ char cmd = 255;
+ int ret;
+ D("gps control fd event");
+ do {
+ ret = read( fd, &cmd, 1 );
+ } while (ret < 0 && errno == EINTR);
+
+ if (cmd == CMD_QUIT) {
+ D("gps thread quitting on demand");
+ goto Exit;
+ }
+ else if (cmd == CMD_START) {
+ if (!started) {
+ D("gps thread starting location_cb=%p", state->callbacks.location_cb);
+ started = 1;
+ nmea_reader_set_callback( reader, state->callbacks.location_cb );
+ }
+ }
+ else if (cmd == CMD_STOP) {
+ if (started) {
+ D("gps thread stopping");
+ started = 0;
+ nmea_reader_set_callback( reader, NULL );
+ }
+ }
+ }
+ else if (fd == gps_fd)
+ {
+ char buff[32];
+ D("gps fd event");
+ for (;;) {
+ int nn, ret;
+
+ ret = read( fd, buff, sizeof(buff) );
+ if (ret < 0) {
+ if (errno == EINTR)
+ continue;
+ if (errno != EWOULDBLOCK)
+ LOGE("error while reading from gps daemon socket: %s:", strerror(errno));
+ break;
+ }
+ D("received %d bytes: %.*s", ret, ret, buff);
+ for (nn = 0; nn < ret; nn++)
+ nmea_reader_addc( reader, buff[nn] );
+ }
+ D("gps fd event end");
+ }
+ else
+ {
+ LOGE("epoll_wait() returned unkown fd %d ?", fd);
+ }
+ }
+ }
+ }
+Exit:
+ return NULL;
+}
+
+
+static void
+gps_state_init( GpsState* state )
+{
+ state->init = 1;
+ state->control[0] = -1;
+ state->control[1] = -1;
+ state->fd = -1;
+
+ state->fd = qemud_channel_open(QEMU_CHANNEL_NAME);
+
+ if (state->fd < 0) {
+ D("no gps emulation detected");
+ return;
+ }
+
+ D("gps emulation will read from '%s' qemud channel", QEMU_CHANNEL_NAME );
+
+ if ( socketpair( AF_LOCAL, SOCK_STREAM, 0, state->control ) < 0 ) {
+ LOGE("could not create thread control socket pair: %s", strerror(errno));
+ goto Fail;
+ }
+
+ if ( pthread_create( &state->thread, NULL, gps_state_thread, state ) != 0 ) {
+ LOGE("could not create gps thread: %s", strerror(errno));
+ goto Fail;
+ }
+
+ D("gps state initialized");
+ return;
+
+Fail:
+ gps_state_done( state );
+}
+
+
+/*****************************************************************/
+/*****************************************************************/
+/***** *****/
+/***** I N T E R F A C E *****/
+/***** *****/
+/*****************************************************************/
+/*****************************************************************/
+
+
+static int
+qemu_gps_init(GpsCallbacks* callbacks)
+{
+ GpsState* s = _gps_state;
+
+ if (!s->init)
+ gps_state_init(s);
+
+ if (s->fd < 0)
+ return -1;
+
+ s->callbacks = *callbacks;
+
+ return 0;
+}
+
+static void
+qemu_gps_cleanup(void)
+{
+ GpsState* s = _gps_state;
+
+ if (s->init)
+ gps_state_done(s);
+}
+
+
+static int
+qemu_gps_start()
+{
+ GpsState* s = _gps_state;
+
+ if (!s->init) {
+ D("%s: called with uninitialized state !!", __FUNCTION__);
+ return -1;
+ }
+
+ D("%s: called", __FUNCTION__);
+ gps_state_start(s);
+ return 0;
+}
+
+
+static int
+qemu_gps_stop()
+{
+ GpsState* s = _gps_state;
+
+ if (!s->init) {
+ D("%s: called with uninitialized state !!", __FUNCTION__);
+ return -1;
+ }
+
+ D("%s: called", __FUNCTION__);
+ gps_state_stop(s);
+ return 0;
+}
+
+
+static int
+qemu_gps_inject_time(GpsUtcTime time, int64_t timeReference, int uncertainty)
+{
+ return 0;
+}
+
+static int
+qemu_gps_inject_location(double latitude, double longitude, float accuracy)
+{
+ return 0;
+}
+
+static void
+qemu_gps_delete_aiding_data(GpsAidingData flags)
+{
+}
+
+static int qemu_gps_set_position_mode(GpsPositionMode mode, int fix_frequency)
+{
+ // FIXME - support fix_frequency
+ return 0;
+}
+
+static const void*
+qemu_gps_get_extension(const char* name)
+{
+ // no extensions supported
+ return NULL;
+}
+
+static const GpsInterface qemuGpsInterface = {
+ sizeof(GpsInterface),
+ qemu_gps_init,
+ qemu_gps_start,
+ qemu_gps_stop,
+ qemu_gps_cleanup,
+ qemu_gps_inject_time,
+ qemu_gps_inject_location,
+ qemu_gps_delete_aiding_data,
+ qemu_gps_set_position_mode,
+ qemu_gps_get_extension,
+};
+
+const GpsInterface* gps__get_gps_interface(struct gps_device_t* dev)
+{
+ return &qemuGpsInterface;
+}
+
+static int open_gps(const struct hw_module_t* module, char const* name,
+ struct hw_device_t** device)
+{
+ struct gps_device_t *dev = malloc(sizeof(struct gps_device_t));
+ memset(dev, 0, sizeof(*dev));
+
+ dev->common.tag = HARDWARE_DEVICE_TAG;
+ dev->common.version = 0;
+ dev->common.module = (struct hw_module_t*)module;
+// dev->common.close = (int (*)(struct hw_device_t*))close_lights;
+ dev->get_gps_interface = gps__get_gps_interface;
+
+ *device = (struct hw_device_t*)dev;
+ return 0;
+}
+
+
+static struct hw_module_methods_t gps_module_methods = {
+ .open = open_gps
+};
+
+const struct hw_module_t HAL_MODULE_INFO_SYM = {
+ .tag = HARDWARE_MODULE_TAG,
+ .version_major = 1,
+ .version_minor = 0,
+ .id = GPS_HARDWARE_MODULE_ID,
+ .name = "Goldfish GPS Module",
+ .author = "The Android Open Source Project",
+ .methods = &gps_module_methods,
+};
diff --git a/emulator/mksdcard/MODULE_LICENSE_BSD b/emulator/mksdcard/MODULE_LICENSE_BSD
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/emulator/mksdcard/MODULE_LICENSE_BSD
diff --git a/emulator/mksdcard/NOTICE b/emulator/mksdcard/NOTICE
new file mode 100644
index 0000000..e4f5db9
--- /dev/null
+++ b/emulator/mksdcard/NOTICE
@@ -0,0 +1,23 @@
+Copyright 2007, The Android Open Source Project
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of Google Inc. nor the names of its contributors may
+ be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY Google Inc. ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+EVENT SHALL Google Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/eventanalyzer/.gitignore b/eventanalyzer/.gitignore
new file mode 100644
index 0000000..ba077a4
--- /dev/null
+++ b/eventanalyzer/.gitignore
@@ -0,0 +1 @@
+bin
diff --git a/files/ant_rules_r1.xml b/files/ant_rules_r1.xml
index 675017c..9ff30f3 100644
--- a/files/ant_rules_r1.xml
+++ b/files/ant_rules_r1.xml
@@ -242,6 +242,10 @@
value="${tested.project.absolute.dir}/bin/classes" else=".">
<isset property="tested.project.absolute.dir" />
</condition>
+ <condition property="extensible.libs.classpath"
+ value="${tested.project.absolute.dir}/libs" else="./libs">
+ <isset property="tested.project.absolute.dir" />
+ </condition>
<javac encoding="ascii" target="1.5" debug="true" extdirs=""
destdir="${out.classes.absolute.dir}"
bootclasspathref="android.target.classpath"
@@ -250,6 +254,7 @@
<src path="${gen.absolute.dir}" />
<classpath>
<fileset dir="${external.libs.absolute.dir}" includes="*.jar" />
+ <fileset dir="${extensible.libs.classpath}" includes="*.jar" />
</classpath>
</javac>
</target>
diff --git a/files/ant_rules_r2.xml b/files/ant_rules_r2.xml
index 6e48796..ffd7c41 100644
--- a/files/ant_rules_r2.xml
+++ b/files/ant_rules_r2.xml
@@ -244,6 +244,10 @@
value="${tested.project.absolute.dir}/bin/classes" else=".">
<isset property="tested.project.absolute.dir" />
</condition>
+ <condition property="extensible.libs.classpath"
+ value="${tested.project.absolute.dir}/libs" else="./libs">
+ <isset property="tested.project.absolute.dir" />
+ </condition>
<javac encoding="ascii" target="1.5" debug="true" extdirs=""
destdir="${out.classes.absolute.dir}"
bootclasspathref="android.target.classpath"
@@ -254,6 +258,7 @@
<src refid="android.libraries.src" />
<classpath>
<fileset dir="${external.libs.absolute.dir}" includes="*.jar" />
+ <fileset dir="${extensible.libs.classpath}" includes="*.jar" />
</classpath>
</javac>
</target>
diff --git a/files/ant_test_rules_r2.xml b/files/ant_test_rules_r2.xml
index 78503ae..00ebfea 100644
--- a/files/ant_test_rules_r2.xml
+++ b/files/ant_test_rules_r2.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project name="android_test_rules" default="run-tests">
- <import file="android_rules.xml" />
+ <import file="ant_rules_r2.xml" />
<property name="tested.project.absolute.dir" location="${tested.project.dir}" />
<property name="instrumentation.dir" value="instrumented" />
diff --git a/files/tools_source.properties b/files/tools_source.properties
index 47cffcf..dc91174 100644
--- a/files/tools_source.properties
+++ b/files/tools_source.properties
@@ -1,2 +1,2 @@
Pkg.UserSrc=false
-Pkg.Revision=6
+Pkg.Revision=7
diff --git a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSource.java b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSource.java
index 415cba5..a7bc3f3 100755
--- a/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSource.java
+++ b/sdkmanager/libs/sdklib/src/com/android/sdklib/internal/repository/RepoSource.java
@@ -160,6 +160,7 @@ public class RepoSource implements IDescription {
monitor.incProgress(1);
mFetchError = null;
+ Boolean[] validatorFound = new Boolean[] { Boolean.FALSE };
String[] validationError = new String[] { null };
Exception[] exception = new Exception[] { null };
ByteArrayInputStream xml = fetchUrl(url, exception);
@@ -168,17 +169,23 @@ public class RepoSource implements IDescription {
String validatedUri = null;
if (xml != null) {
monitor.setDescription("Validate XML");
- String uri = validateXml(xml, url, validationError);
+ String uri = validateXml(xml, url, validationError, validatorFound);
if (uri != null) {
+ // Validation was successful
validatedDoc = getDocument(xml, monitor);
validatedUri = uri;
- } else {
+ } else if (validatorFound[0].equals(Boolean.TRUE)) {
+ // An XML validator was found and the XML failed to validate.
+ // Let's see if we can find an alternate tools upgrade to perform.
validatedDoc = findAlternateToolsXml(xml);
if (validatedDoc != null) {
validationError[0] = null; // remove error from XML validation
validatedUri = SdkRepository.NS_SDK_REPOSITORY;
usingAlternateXml = true;
}
+ } else {
+ // Validation failed because this JVM lacks a proper XML Validator
+ mFetchError = "No suitable XML Schema Validator could be found in your Java environment. Please update your version of Java.";
}
}
@@ -192,17 +199,24 @@ public class RepoSource implements IDescription {
xml = fetchUrl(url, exception);
if (xml != null) {
- String uri = validateXml(xml, url, validationError);
+ String uri = validateXml(xml, url, validationError, validatorFound);
if (uri != null) {
+ // Validation was successful
+ validationError[0] = null; // remove error from previous XML validation
validatedDoc = getDocument(xml, monitor);
validatedUri = uri;
- } else {
+ } else if (validatorFound[0].equals(Boolean.TRUE)) {
+ // An XML validator was found and the XML failed to validate.
+ // Let's see if we can find an alternate tools upgrade to perform.
validatedDoc = findAlternateToolsXml(xml);
if (validatedDoc != null) {
validationError[0] = null; // remove error from XML validation
validatedUri = SdkRepository.NS_SDK_REPOSITORY;
usingAlternateXml = true;
}
+ } else {
+ // Validation failed because this JVM lacks a proper XML Validator
+ mFetchError = "No suitable XML Schema Validator could be found in your Java environment. Please update your version of Java.";
}
}
@@ -249,9 +263,29 @@ public class RepoSource implements IDescription {
}
if (usingAlternateXml) {
- String info = "This repository requires a more recent version of the Tools. Please update.";
+
+ // Is the manager running from inside ADT?
+ // We check that com.android.ide.eclipse.adt.AdtPlugin exists using reflection.
+
+ boolean isADT = false;
+ try {
+ Class<?> adt = Class.forName("com.android.ide.eclipse.adt.AdtPlugin"); //$NON-NLS-1$
+ isADT = (adt != null);
+ } catch (ClassNotFoundException e) {
+ // pass
+ }
+
+ String info;
+ if (isADT) {
+ info = "This repository requires a more recent version of ADT. Please update the Eclipse Android plugin.";
+ mDescription = "This repository requires a more recent version of ADT, the Eclipse Android plugin.\nYou must update it before you can see other new packages.";
+
+ } else {
+ info = "This repository requires a more recent version of the Tools. Please update.";
+ mDescription = "This repository requires a more recent version of the Tools.\nYou must update it before you can see other new packages.";
+ }
+
mFetchError = mFetchError == null ? info : mFetchError + ". " + info;
- mDescription = "This repository requires a more recent version of the Tools.\nYou must update it before you can see other new packages.";
}
monitor.incProgress(1);
@@ -339,7 +373,8 @@ public class RepoSource implements IDescription {
* If the XML was correctly validated, returns the schema that worked.
* If no schema validated the XML, returns null.
*/
- private String validateXml(ByteArrayInputStream xml, String url, String[] outError) {
+ private String validateXml(ByteArrayInputStream xml, String url,
+ String[] outError, Boolean[] validatorFound) {
String lastError = null;
String extraError = null;
@@ -349,9 +384,11 @@ public class RepoSource implements IDescription {
if (validator == null) {
lastError = "XML verification failed for %1$s.\nNo suitable XML Schema Validator could be found in your Java environment. Please consider updating your version of Java.";
+ validatorFound[0] = Boolean.FALSE;
continue;
}
+ validatorFound[0] = Boolean.TRUE;
xml.reset();
// Validation throws a bunch of possible Exceptions on failure.
validator.validate(new StreamSource(xml));
diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RemotePackagesPage.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RemotePackagesPage.java
index b9d7157..b687f5c 100755
--- a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RemotePackagesPage.java
+++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/repository/RemotePackagesPage.java
@@ -112,11 +112,11 @@ public class RemotePackagesPage extends Composite implements ISdkListener {
mDescriptionLabel = new Label(mDescriptionContainer, SWT.NONE);
mDescriptionLabel.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 1, 1));
- mDescriptionLabel.setText("Line1\nLine2\nLine3");
+ mDescriptionLabel.setText("Line1\nLine2\nLine3"); //$NON-NLS-1$
mAddSiteButton = new Button(parent, SWT.NONE);
- mAddSiteButton.setText("Add Site...");
- mAddSiteButton.setToolTipText("Allows you to enter a new user external site. " +
+ mAddSiteButton.setText("Add Add-on Site...");
+ mAddSiteButton.setToolTipText("Allows you to enter a new add-on site. " +
"Such site can only contribute add-ons and extra packages.");
mAddSiteButton.addSelectionListener(new SelectionAdapter() {
@Override
@@ -126,9 +126,9 @@ public class RemotePackagesPage extends Composite implements ISdkListener {
});
mDeleteSiteButton = new Button(parent, SWT.NONE);
- mDeleteSiteButton.setText("Delete Site...");
- mDeleteSiteButton.setToolTipText("Allows you to remove an external site. " +
- "Built-in sites cannot be removed.");
+ mDeleteSiteButton.setText("Delete Add-on Site...");
+ mDeleteSiteButton.setToolTipText("Allows you to remove an add-on site. " +
+ "Built-in default sites cannot be removed.");
mDeleteSiteButton.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
@@ -327,28 +327,38 @@ public class RemotePackagesPage extends Composite implements ISdkListener {
private void onAddSiteSelected() {
final RepoSource[] knowSources = mUpdaterData.getSources().getSources();
- String title = "Add Site URL";
- String msg = "Please enter the URL of the repository.xml for the new site:";
+ String title = "Add Add-on Site URL";
+
+ String msg =
+ "This dialog lets you add the URL of a new add-on site.\n" +
+ "\n" +
+ "An add-on site can only provide new add-ons or \"user\" packages.\n" +
+ "Add-on sites cannot provide standard Android platforms, docs or samples packages.\n" +
+ "Inserting a URL here will not allow you to clone an official Android repository.\n" +
+ "\n" +
+ "Please enter the URL of the repository.xml for the new add-on site:";
InputDialog dlg = new InputDialog(getShell(), title, msg, null, new IInputValidator() {
public String isValid(String newText) {
if (newText == null || newText.length() == 0) {
- return "Please enter an URL.";
+ return "Error: URL field is empty. Please enter a URL.";
}
// A URL should have one of the following prefixes
- if (!newText.startsWith("file://") &&
- !newText.startsWith("ftp://") &&
- !newText.startsWith("http://") &&
- !newText.startsWith("https://")) {
- return "The URL must start by one of file://, ftp://, http:// or https://";
+ if (!newText.startsWith("file://") && //$NON-NLS-1$
+ !newText.startsWith("ftp://") && //$NON-NLS-1$
+ !newText.startsWith("http://") && //$NON-NLS-1$
+ !newText.startsWith("https://")) { //$NON-NLS-1$
+ return "Error: The URL must start by one of file://, ftp://, http:// or https://";
}
- // Reject URLs that are already in the source list
+ // Reject URLs that are already in the source list.
+ // URLs are generally case-insensitive (except for file:// where it all depends
+ // on the current OS so we'll ignore this case.)
for (RepoSource s : knowSources) {
- if (newText.equals(s.getUrl())) {
- return "This site is already listed.";
+ if (newText.equalsIgnoreCase(s.getUrl())) {
+ return "Error : This site is already listed.";
}
}
@@ -372,9 +382,9 @@ public class RemotePackagesPage extends Composite implements ISdkListener {
if (c instanceof RepoSource && ((RepoSource) c).isUserSource()) {
RepoSource source = (RepoSource) c;
- String title = "Delete Site?";
+ String title = "Delete Add-on Site?";
- String msg = String.format("Are you sure you want to delete the site '%1$s'?",
+ String msg = String.format("Are you sure you want to delete the add-on site '%1$s'?",
source.getUrl());
if (MessageDialog.openQuestion(getShell(), title, msg)) {
diff --git a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdCreationDialog.java b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdCreationDialog.java
index 01c5dcd..e3724be 100644
--- a/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdCreationDialog.java
+++ b/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/internal/widgets/AvdCreationDialog.java
@@ -215,7 +215,7 @@ final class AvdCreationDialog extends GridDialog {
@Override
protected Control createContents(Composite parent) {
Control control = super.createContents(parent);
- getShell().setText("Create new AVD");
+ getShell().setText("Create new Android Virtual Device (AVD)");
mOkButton = getButton(IDialogConstants.OK_ID);
validatePage();
@@ -230,16 +230,22 @@ final class AvdCreationDialog extends GridDialog {
Label label = new Label(parent, SWT.NONE);
label.setText("Name:");
+ String tooltip = "Name of the new Android Virtual Device";
+ label.setToolTipText(tooltip);
mAvdName = new Text(parent, SWT.BORDER);
mAvdName.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
mAvdName.addModifyListener(new CreateNameModifyListener());
+ mAvdName.setToolTipText(tooltip);
label = new Label(parent, SWT.NONE);
label.setText("Target:");
+ tooltip = "The version of Android to use in the virtual device";
+ label.setToolTipText(tooltip);
mTargetCombo = new Combo(parent, SWT.READ_ONLY | SWT.DROP_DOWN);
mTargetCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ mTargetCombo.setToolTipText(tooltip);
mTargetCombo.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
@@ -261,6 +267,7 @@ final class AvdCreationDialog extends GridDialog {
mSdCardSizeRadio = new Button(sdCardGroup, SWT.RADIO);
mSdCardSizeRadio.setText("Size:");
+ mSdCardSizeRadio.setToolTipText("Create a new SD Card file");
mSdCardSizeRadio.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent arg0) {
@@ -276,6 +283,7 @@ final class AvdCreationDialog extends GridDialog {
mSdCardSize.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
mSdCardSize.addVerifyListener(mDigitVerifier);
mSdCardSize.addModifyListener(validateListener);
+ mSdCardSize.setToolTipText("Size of the new SD Card file (must be at least 9 MiB)");
mSdCardSizeCombo = new Combo(sdCardGroup, SWT.DROP_DOWN | SWT.READ_ONLY);
mSdCardSizeCombo.add("KiB");
@@ -285,13 +293,16 @@ final class AvdCreationDialog extends GridDialog {
mSdCardFileRadio = new Button(sdCardGroup, SWT.RADIO);
mSdCardFileRadio.setText("File:");
+ mSdCardFileRadio.setToolTipText("Use an existing file for the SD Card");
mSdCardFile = new Text(sdCardGroup, SWT.BORDER);
mSdCardFile.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
mSdCardFile.addModifyListener(validateListener);
+ mSdCardFile.setToolTipText("File to use for the SD Card");
mBrowseSdCard = new Button(sdCardGroup, SWT.PUSH);
mBrowseSdCard.setText("Browse...");
+ mBrowseSdCard.setToolTipText("Select the file to use for the SD Card");
mBrowseSdCard.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent arg0) {
@@ -315,6 +326,7 @@ final class AvdCreationDialog extends GridDialog {
mSkinListRadio = new Button(skinGroup, SWT.RADIO);
mSkinListRadio.setText("Built-in:");
+ mSkinListRadio.setToolTipText("Select an emulated screen size provided by the current Android target");
mSkinListRadio.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent arg0) {
@@ -337,11 +349,13 @@ final class AvdCreationDialog extends GridDialog {
mSkinSizeRadio = new Button(skinGroup, SWT.RADIO);
mSkinSizeRadio.setText("Resolution:");
+ mSkinSizeRadio.setToolTipText("Select a custom emulated screen size");
mSkinSizeWidth = new Text(skinGroup, SWT.BORDER);
mSkinSizeWidth.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
mSkinSizeWidth.addVerifyListener(mDigitVerifier);
mSkinSizeWidth.addModifyListener(validateListener);
+ mSkinSizeWidth.setToolTipText("Width in pixels of the emulated screen size");
new Label(skinGroup, SWT.NONE).setText("x");
@@ -349,6 +363,7 @@ final class AvdCreationDialog extends GridDialog {
mSkinSizeHeight.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
mSkinSizeHeight.addVerifyListener(mDigitVerifier);
mSkinSizeHeight.addModifyListener(validateListener);
+ mSkinSizeHeight.setToolTipText("Height in pixels of the emulated screen size");
mSkinListRadio.setSelection(true);
enableSkinWidgets(true);
@@ -373,6 +388,7 @@ final class AvdCreationDialog extends GridDialog {
Button b = new Button(hwButtons, SWT.PUSH | SWT.FLAT);
b.setText("New...");
+ b.setToolTipText("Add a new hardware property");
b.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
b.addSelectionListener(new SelectionAdapter() {
@Override
@@ -390,6 +406,7 @@ final class AvdCreationDialog extends GridDialog {
});
mDeleteHardwareProp = new Button(hwButtons, SWT.PUSH | SWT.FLAT);
mDeleteHardwareProp.setText("Delete");
+ mDeleteHardwareProp.setToolTipText("Delete the selected hardware property");
mDeleteHardwareProp.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
mDeleteHardwareProp.addSelectionListener(new SelectionAdapter() {
@Override
@@ -407,9 +424,9 @@ final class AvdCreationDialog extends GridDialog {
// --- end hardware group
mForceCreation = new Button(parent, SWT.CHECK);
- mForceCreation.setText("Force create");
- mForceCreation.setToolTipText("Select this to override any existing AVD");
- mForceCreation.setLayoutData(new GridData(GridData.END, GridData.CENTER,
+ mForceCreation.setText("Override the existing AVD with the same name");
+ mForceCreation.setToolTipText("There's already an AVD with the same name. Check this to delete it and replace it by the new AVD.");
+ mForceCreation.setLayoutData(new GridData(GridData.BEGINNING, GridData.CENTER,
true, false, 2, 1));
mForceCreation.setEnabled(false);
mForceCreation.addSelectionListener(validateListener);
@@ -761,7 +778,7 @@ final class AvdCreationDialog extends GridDialog {
}
if (value < 9 * 1024 * 1024) {
- error = "SD Card size must be at least 9MB";
+ error = "SD Card size must be at least 9 MiB";
}
} catch (NumberFormatException e) {
// will never happen thanks to the VerifyListener.
@@ -792,7 +809,7 @@ final class AvdCreationDialog extends GridDialog {
if (avdMatch != null && !mForceCreation.getSelection()) {
error = String.format(
"The AVD name '%s' is already used.\n" +
- "Check \"Force create\" to override existing AVD.",
+ "Check \"Override the existing AVD\" to delete the existing one.",
avdName);
}
}