diff options
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); } } |