From ad30a85cfce580bcde7287221db3b1aa56230897 Mon Sep 17 00:00:00 2001 From: Xavier Ducrohet <> Date: Fri, 27 Mar 2009 14:31:26 -0700 Subject: [PATCH 01/45] AI 143143: Update ADT changes.txt with JUnit features, and properly restrict ADT package access. BUG=1743054 Automated import of CL 143143 --- tools/eclipse/changes.txt | 1 + .../com.android.ide.eclipse.adt/META-INF/MANIFEST.MF | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/tools/eclipse/changes.txt b/tools/eclipse/changes.txt index 8cd843e20..02d907585 100644 --- a/tools/eclipse/changes.txt +++ b/tools/eclipse/changes.txt @@ -5,6 +5,7 @@ * Project properties (right click project in Package Explorer, then "Properties"), lets you edit project target. * New Launch configuration option to choose debug deployment target. - Ability to export multiple apk from one project, using resource filters. See the 'android' property for Android projects. +- Support for running JUnit tests on a device/emulator from a new "Android JUnit tests" launch configuration. 0.8.1: diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF b/tools/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF index c0dfcefd5..0ec97aa38 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF @@ -45,16 +45,16 @@ Require-Bundle: com.android.ide.eclipse.ddms, org.eclipse.ltk.core.refactoring, org.eclipse.ltk.ui.refactoring Eclipse-LazyStart: true -Export-Package: com.android.ide.eclipse.adt, +Export-Package: com.android.ide.eclipse.adt;x-friends:="com.android.ide.eclipse.tests", com.android.ide.eclipse.adt.build;x-friends:="com.android.ide.eclipse.tests", com.android.ide.eclipse.adt.launch;x-friends:="com.android.ide.eclipse.tests", com.android.ide.eclipse.adt.project;x-friends:="com.android.ide.eclipse.tests", com.android.ide.eclipse.adt.project.internal;x-friends:="com.android.ide.eclipse.tests", com.android.ide.eclipse.adt.sdk;x-friends:="com.android.ide.eclipse.tests", com.android.ide.eclipse.adt.wizards.newproject;x-friends:="com.android.ide.eclipse.tests", - com.android.ide.eclipse.common, - com.android.ide.eclipse.common.project, - com.android.ide.eclipse.common.resources, + com.android.ide.eclipse.common;x-friends:="com.android.ide.eclipse.tests", + com.android.ide.eclipse.common.project;x-friends:="com.android.ide.eclipse.tests", + com.android.ide.eclipse.common.resources;x-friends:="com.android.ide.eclipse.tests", com.android.ide.eclipse.editors;x-friends:="com.android.ide.eclipse.tests", com.android.ide.eclipse.editors.descriptors;x-friends:="com.android.ide.eclipse.tests", com.android.ide.eclipse.editors.layout;x-friends:="com.android.ide.eclipse.tests", From fe8bec70caf01fa91ae3dd05bc441ba7d7b66929 Mon Sep 17 00:00:00 2001 From: Xavier Ducrohet <> Date: Fri, 27 Mar 2009 15:05:58 -0700 Subject: [PATCH 02/45] AI 143149: Make ADT look for javadoc in docs/reference for the optional libraries (to match the base docs). BUG=1743022 Automated import of CL 143149 --- .../com/android/ide/eclipse/common/AndroidConstants.java | 5 +++-- .../libs/sdklib/src/com/android/sdklib/AddOnTarget.java | 3 ++- .../libs/sdklib/src/com/android/sdklib/SdkConstants.java | 2 ++ .../sdkuilib/src/com/android/sdkuilib/AvdSelector.java | 8 ++++---- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/AndroidConstants.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/AndroidConstants.java index 226357f7a..d0d8ae3af 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/AndroidConstants.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/AndroidConstants.java @@ -90,7 +90,7 @@ public class AndroidConstants { /** Name of the android sources directory */ public static final String FD_ANDROID_SOURCES = "sources"; //$NON-NLS-1$ - + /** Resource java class filename, i.e. "R.java" */ public final static String FN_RESOURCE_CLASS = "R.java"; //$NON-NLS-1$ /** Resource class file filename, i.e. "R.class" */ @@ -128,7 +128,8 @@ public class AndroidConstants { public final static String WS_ASSETS = WS_SEP + SdkConstants.FD_ASSETS; /** Leaf of the javaDoc folder. Does not start with a separator. */ - public final static String WS_JAVADOC_FOLDER_LEAF = SdkConstants.FD_DOCS + "/reference"; //$NON-NLS-1$ + public final static String WS_JAVADOC_FOLDER_LEAF = SdkConstants.FD_DOCS + "/" + + SdkConstants.FD_DOCS_REFERENCE; //$NON-NLS-1$ /** Path of the samples directory relative to the sdk folder. * This is an OS path, ending with a separator. diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java index 0a5910734..d1ae343d5 100644 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java @@ -153,7 +153,8 @@ final class AddOnTarget implements IAndroidTarget { case SKINS: return mLocation + SdkConstants.OS_SKINS_FOLDER; case DOCS: - return mLocation + SdkConstants.FD_DOCS + File.separator; + return mLocation + SdkConstants.FD_DOCS + File.separator + + SdkConstants.FD_DOCS_REFERENCE; default : return mBasePlatform.getPath(pathId); } diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java index 00594d12f..9eb6ade6b 100644 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java @@ -143,6 +143,8 @@ public final class SdkConstants { public final static String FD_LIB = "lib"; /** Name of the SDK docs folder. */ public final static String FD_DOCS = "docs"; + /** Name of the doc folder containing API reference doc (javadoc) */ + public static final String FD_DOCS_REFERENCE = "reference"; /** Name of the SDK images folder. */ public final static String FD_IMAGES = "images"; /** Name of the SDK skins folder. */ diff --git a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/AvdSelector.java b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/AvdSelector.java index 67c70a676..d62c231c1 100644 --- a/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/AvdSelector.java +++ b/tools/sdkmanager/libs/sdkuilib/src/com/android/sdkuilib/AvdSelector.java @@ -89,9 +89,9 @@ public final class AvdSelector { final TableColumn column1 = new TableColumn(mTable, SWT.NONE); column1.setText("Target Name"); final TableColumn column2 = new TableColumn(mTable, SWT.NONE); - column2.setText("API Level"); + column2.setText("SDK"); final TableColumn column3 = new TableColumn(mTable, SWT.NONE); - column3.setText("SDK"); + column3.setText("API Level"); adjustColumnsWidth(mTable, column0, column1, column2, column3); setupSelectionListener(mTable); @@ -235,8 +235,8 @@ public final class AvdSelector { Rectangle r = table.getClientArea(); column0.setWidth(r.width * 30 / 100); // 30% column1.setWidth(r.width * 45 / 100); // 45% - column2.setWidth(r.width * 15 / 100); // 15% - column3.setWidth(r.width * 10 / 100); // 10% + column2.setWidth(r.width * 10 / 100); // 10% + column3.setWidth(r.width * 15 / 100); // 15% } }); } From 729ff799f77fff783ba1fa46d9adb57e500e4150 Mon Sep 17 00:00:00 2001 From: Jack Palevich <> Date: Fri, 27 Mar 2009 15:49:45 -0700 Subject: [PATCH 03/45] AI 143256: Make the Term emulator work with the most recent keyboard IME. + Makes the "Enter" key work again. + Makes the "Delete" key delete just one character each time you press it instead of two. BUG=1615131 Automated import of CL 143256 --- apps/Term/src/com/android/term/Term.java | 36 +++++++++--------------- 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/apps/Term/src/com/android/term/Term.java b/apps/Term/src/com/android/term/Term.java index d74159b90..1f43843a3 100644 --- a/apps/Term/src/com/android/term/Term.java +++ b/apps/Term/src/com/android/term/Term.java @@ -548,16 +548,6 @@ public class Term extends Activity { + controlKey + " 6 ==> Control-^"). show(); } - - private void print(String msg) { - char[] chars = msg.toCharArray(); - int len = chars.length; - byte[] bytes = new byte[len]; - for (int i = 0; i < len; i++) { - bytes[i] = (byte) chars[i]; - } - mEmulatorView.append(bytes, 0, len); - } } @@ -2707,8 +2697,13 @@ class EmulatorView extends View implements GestureDetector.OnGestureListener { return null; } - public boolean hideStatusIcon() { - return true; + public boolean performEditorAction(int actionCode) { + if(actionCode == EditorInfo.IME_ACTION_UNSPECIFIED) { + // The "return" key has been pressed on the IME. + sendText("\n"); + return true; + } + return false; } public boolean performContextMenuAction(int id) { @@ -2720,13 +2715,12 @@ class EmulatorView extends View implements GestureDetector.OnGestureListener { } public boolean sendKeyEvent(KeyEvent event) { - switch(event.getKeyCode()) { - case KeyEvent.KEYCODE_ENTER: - sendChar('\r'); - break; - case KeyEvent.KEYCODE_DEL: - sendChar(127); - break; + if (event.getAction() == KeyEvent.ACTION_DOWN) { + switch(event.getKeyCode()) { + case KeyEvent.KEYCODE_DEL: + sendChar(127); + break; + } } return true; } @@ -2739,10 +2733,6 @@ class EmulatorView extends View implements GestureDetector.OnGestureListener { return true; } - public boolean showStatusIcon(String packageName, int resId) { - return true; - } - private void sendChar(int c) { try { mTermOut.write(c); From f739e79bf4387a6accbd066291f7ee082f9c2259 Mon Sep 17 00:00:00 2001 From: Raphael Moll <> Date: Fri, 27 Mar 2009 16:06:03 -0700 Subject: [PATCH 04/45] AI 143259: ADT #1743364: Refactor all wizard classes & their actions together. BUG=1743364 Automated import of CL 143259 --- .../ide/eclipse/adt/wizards/actions/NewXmlFileAction.java | 2 +- .../{project => wizards/actions}/NewXmlFileWizardAction.java | 4 ++-- .../wizards/newxmlfile}/NewXmlFileCreationPage.java | 3 ++- .../wizards => adt/wizards/newxmlfile}/NewXmlFileWizard.java | 4 ++-- 4 files changed, 7 insertions(+), 6 deletions(-) rename tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/{project => wizards/actions}/NewXmlFileWizardAction.java (94%) rename tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/{editors/wizards => adt/wizards/newxmlfile}/NewXmlFileCreationPage.java (99%) rename tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/{editors/wizards => adt/wizards/newxmlfile}/NewXmlFileWizard.java (98%) diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/actions/NewXmlFileAction.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/actions/NewXmlFileAction.java index 8c4a115b4..d1530d4ea 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/actions/NewXmlFileAction.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/actions/NewXmlFileAction.java @@ -16,7 +16,7 @@ package com.android.ide.eclipse.adt.wizards.actions; -import com.android.ide.eclipse.editors.wizards.NewXmlFileWizard; +import com.android.ide.eclipse.adt.wizards.newxmlfile.NewXmlFileWizard; import org.eclipse.jface.action.IAction; import org.eclipse.ui.IWorkbenchWizard; diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/NewXmlFileWizardAction.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/actions/NewXmlFileWizardAction.java similarity index 94% rename from tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/NewXmlFileWizardAction.java rename to tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/actions/NewXmlFileWizardAction.java index c117b4e57..20cfc8275 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/NewXmlFileWizardAction.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/actions/NewXmlFileWizardAction.java @@ -14,9 +14,9 @@ * limitations under the License. */ -package com.android.ide.eclipse.adt.project; +package com.android.ide.eclipse.adt.wizards.actions; -import com.android.ide.eclipse.editors.wizards.NewXmlFileWizard; +import com.android.ide.eclipse.adt.wizards.newxmlfile.NewXmlFileWizard; import org.eclipse.jface.action.IAction; import org.eclipse.jface.viewers.ISelection; diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/NewXmlFileCreationPage.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newxmlfile/NewXmlFileCreationPage.java similarity index 99% rename from tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/NewXmlFileCreationPage.java rename to tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newxmlfile/NewXmlFileCreationPage.java index 83ab59be1..f3cbfa221 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/NewXmlFileCreationPage.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newxmlfile/NewXmlFileCreationPage.java @@ -15,7 +15,7 @@ */ -package com.android.ide.eclipse.editors.wizards; +package com.android.ide.eclipse.adt.wizards.newxmlfile; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.sdk.AndroidTargetData; @@ -31,6 +31,7 @@ import com.android.ide.eclipse.editors.resources.configurations.FolderConfigurat import com.android.ide.eclipse.editors.resources.configurations.ResourceQualifier; import com.android.ide.eclipse.editors.resources.descriptors.ResourcesDescriptors; import com.android.ide.eclipse.editors.resources.manager.ResourceFolderType; +import com.android.ide.eclipse.editors.wizards.ConfigurationSelector; import com.android.ide.eclipse.editors.wizards.ConfigurationSelector.ConfigurationState; import com.android.sdklib.IAndroidTarget; import com.android.sdklib.SdkConstants; diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/NewXmlFileWizard.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newxmlfile/NewXmlFileWizard.java similarity index 98% rename from tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/NewXmlFileWizard.java rename to tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newxmlfile/NewXmlFileWizard.java index 125102b96..d7e43cfd7 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/NewXmlFileWizard.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newxmlfile/NewXmlFileWizard.java @@ -16,11 +16,11 @@ -package com.android.ide.eclipse.editors.wizards; +package com.android.ide.eclipse.adt.wizards.newxmlfile; import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.ide.eclipse.adt.wizards.newxmlfile.NewXmlFileCreationPage.TypeInfo; import com.android.ide.eclipse.editors.IconFactory; -import com.android.ide.eclipse.editors.wizards.NewXmlFileCreationPage.TypeInfo; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; From 3141ffd322e03b0d7d71f4e3a3052aec2418a54e Mon Sep 17 00:00:00 2001 From: Xavier Ducrohet <> Date: Fri, 27 Mar 2009 18:28:38 -0700 Subject: [PATCH 05/45] AI 143407: Prevent reinstalling APKs during launch if they have not been recompiled since the previous launch. BUG=1743026 Automated import of CL 143407 --- .../ide/eclipse/adt/build/ApkBuilder.java | 4 + .../adt/launch/AndroidLaunchController.java | 46 +++- .../adt/project/ApkInstallManager.java | 207 ++++++++++++++++++ 3 files changed, 250 insertions(+), 7 deletions(-) create mode 100644 tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/ApkInstallManager.java diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java index 1edcf79fd..47ea3e731 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java @@ -18,6 +18,7 @@ package com.android.ide.eclipse.adt.build; import com.android.ide.eclipse.adt.AdtConstants; import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.ide.eclipse.adt.project.ApkInstallManager; import com.android.ide.eclipse.adt.project.ProjectHelper; import com.android.ide.eclipse.adt.sdk.AndroidTargetData; import com.android.ide.eclipse.adt.sdk.Sdk; @@ -551,6 +552,9 @@ public class ApkBuilder extends BaseBuilder { // and store it saveProjectBooleanProperty(PROPERTY_BUILD_APK, mBuildFinalPackage); + // reset the installation manager to force new installs of this project + ApkInstallManager.getInstance().resetInstallationFor(project); + AdtPlugin.printBuildToConsole(AdtConstants.BUILD_VERBOSE, getProject(), "Build Success!"); } diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AndroidLaunchController.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AndroidLaunchController.java index fafc4020b..b6c7640c7 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AndroidLaunchController.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/AndroidLaunchController.java @@ -32,6 +32,7 @@ import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.launch.AndroidLaunchConfiguration.TargetMode; import com.android.ide.eclipse.adt.launch.DelayedLaunchInfo.InstallRetryMode; import com.android.ide.eclipse.adt.launch.DeviceChooserDialog.DeviceChooserResponse; +import com.android.ide.eclipse.adt.project.ApkInstallManager; import com.android.ide.eclipse.adt.project.ProjectHelper; import com.android.ide.eclipse.adt.sdk.Sdk; import com.android.ide.eclipse.common.project.AndroidManifestParser; @@ -762,13 +763,46 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener /** - * Syncs the application on the device/emulator. + * If needed, syncs the application and all its dependencies on the device/emulator. * * @param launchInfo The Launch information object. * @param device the device on which to sync the application * @return true if the install succeeded. */ private boolean syncApp(DelayedLaunchInfo launchInfo, IDevice device) { + boolean alreadyInstalled = ApkInstallManager.getInstance().isApplicationInstalled( + launchInfo.getProject(), device); + + if (alreadyInstalled) { + AdtPlugin.printToConsole(launchInfo.getProject(), + "Application already deployed. No need to reinstall."); + } else { + if (doSyncApp(launchInfo, device) == false) { + return false; + } + } + + // The app is now installed, now try the dependent projects + for (DelayedLaunchInfo dependentLaunchInfo : getDependenciesLaunchInfo(launchInfo)) { + String msg = String.format("Project dependency found, installing: %s", + dependentLaunchInfo.getProject().getName()); + AdtPlugin.printToConsole(launchInfo.getProject(), msg); + if (syncApp(dependentLaunchInfo, device) == false) { + return false; + } + } + + return true; + } + + /** + * Syncs the application on the device/emulator. + * + * @param launchInfo The Launch information object. + * @param device the device on which to sync the application + * @return true if the install succeeded. + */ + private boolean doSyncApp(DelayedLaunchInfo launchInfo, IDevice device) { SyncService sync = device.getSyncService(); if (sync != null) { IPath path = launchInfo.getPackageFile().getLocation(); @@ -812,12 +846,10 @@ public final class AndroidLaunchController implements IDebugBridgeChangeListener return false; } - // The app is now installed, now try the dependent projects - for (DelayedLaunchInfo dependentLaunchInfo : getDependenciesLaunchInfo(launchInfo)) { - String msg = String.format("Project dependency found, syncing: %s", - dependentLaunchInfo.getProject().getName()); - AdtPlugin.printToConsole(launchInfo.getProject(), msg); - syncApp(dependentLaunchInfo, device); + // if the installation succeeded, we register it. + if (installResult) { + ApkInstallManager.getInstance().registerInstallation( + launchInfo.getProject(), device); } return installResult; diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/ApkInstallManager.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/ApkInstallManager.java new file mode 100644 index 000000000..172c555f4 --- /dev/null +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/ApkInstallManager.java @@ -0,0 +1,207 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php + * + * 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. + */ + +package com.android.ide.eclipse.adt.project; + +import com.android.ddmlib.AndroidDebugBridge; +import com.android.ddmlib.Device; +import com.android.ddmlib.IDevice; +import com.android.ddmlib.AndroidDebugBridge.IDebugBridgeChangeListener; +import com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener; +import com.android.ide.eclipse.editors.resources.manager.ResourceMonitor; +import com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IProjectListener; + +import org.eclipse.core.resources.IProject; + +import java.util.ArrayList; + +/** + * Registers which apk was installed on which device. + *

+ * The goal of this class is to remember the installation of APKs on devices, and provide + * information about whether a new APK should be installed on a device prior to running the + * application from a launch configuration. + *

+ * The manager uses {@link IProject} and {@link IDevice} to identify the target device and the + * (project generating the) APK. This ensures that disconnected and reconnected devices will + * always receive new APKs (since the APK could be uninstalled manually). + *

+ * Manually uninstalling an APK from a connected device will still be a problem, but this should + * be a limited use case. + *

+ * This is a singleton. To get the instance, use {@link #getInstance()} + */ +public class ApkInstallManager implements IDeviceChangeListener, IDebugBridgeChangeListener, + IProjectListener { + + private final static ApkInstallManager sThis = new ApkInstallManager(); + + /** + * Internal struct to associate a project and a device. + */ + private static class ApkInstall { + public ApkInstall(IProject project, IDevice device) { + this.project = project; + this.device = device; + } + IProject project; + IDevice device; + } + + private final ArrayList mInstallList = new ArrayList(); + + public static ApkInstallManager getInstance() { + return sThis; + } + + /** + * Registers an installation of project onto device + * @param project The project that was installed. + * @param device The device that received the installation. + */ + public void registerInstallation(IProject project, IDevice device) { + synchronized (mInstallList) { + mInstallList.add(new ApkInstall(project, device)); + } + } + + /** + * Returns whether a project was installed on the device. + * @param project the project that may have been installed. + * @param device the device that may have received the installation. + * @return + */ + public boolean isApplicationInstalled(IProject project, IDevice device) { + synchronized (mInstallList) { + for (ApkInstall install : mInstallList) { + if (project == install.project && device == install.device) { + return true; + } + } + } + return false; + } + + /** + * Resets registered installations for a specific {@link IProject}. + *

This ensures that {@link #isApplicationInstalled(IProject, IDevice)} will always return + * null for this specified project, for any device. + * @param project the project for which to reset all installations. + */ + public void resetInstallationFor(IProject project) { + synchronized (mInstallList) { + for (int i = 0 ; i < mInstallList.size() ;) { + ApkInstall install = mInstallList.get(i); + if (install.project == project) { + mInstallList.remove(i); + } else { + i++; + } + } + } + } + + private ApkInstallManager() { + AndroidDebugBridge.addDeviceChangeListener(this); + AndroidDebugBridge.addDebugBridgeChangeListener(this); + ResourceMonitor.getMonitor().addProjectListener(this); + } + + /* + * Responds to a bridge change by clearing the full installation list. + * (non-Javadoc) + * @see com.android.ddmlib.AndroidDebugBridge.IDebugBridgeChangeListener#bridgeChanged(com.android.ddmlib.AndroidDebugBridge) + */ + public void bridgeChanged(AndroidDebugBridge bridge) { + // the bridge changed, there is no way to know which IDevice will be which. + // We reset everything + synchronized (mInstallList) { + mInstallList.clear(); + } + } + + /* + * Responds to a device being disconnected by removing all installations related to this device. + * (non-Javadoc) + * @see com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener#deviceDisconnected(com.android.ddmlib.Device) + */ + public void deviceDisconnected(Device device) { + synchronized (mInstallList) { + for (int i = 0 ; i < mInstallList.size() ;) { + ApkInstall install = mInstallList.get(i); + if (install.device == device) { + mInstallList.remove(i); + } else { + i++; + } + } + } + } + + /* + * Responds to a close project by resetting all its installation. + * (non-Javadoc) + * @see com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IProjectListener#projectClosed(org.eclipse.core.resources.IProject) + */ + public void projectClosed(IProject project) { + resetInstallationFor(project); + } + + /* + * Responds to a close project by resetting all its installation. + * (non-Javadoc) + * @see com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IProjectListener#projectDeleted(org.eclipse.core.resources.IProject) + */ + public void projectDeleted(IProject project) { + resetInstallationFor(project); + } + + /* + * Does nothing + * (non-Javadoc) + * @see com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener#deviceChanged(com.android.ddmlib.Device, int) + */ + public void deviceChanged(Device device, int changeMask) { + // nothing to do. + } + + /* + * Does nothing + * (non-Javadoc) + * @see com.android.ddmlib.AndroidDebugBridge.IDeviceChangeListener#deviceConnected(com.android.ddmlib.Device) + */ + public void deviceConnected(Device device) { + // nothing to do. + } + + /* + * Does nothing + * (non-Javadoc) + * @see com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IProjectListener#projectOpened(org.eclipse.core.resources.IProject) + */ + public void projectOpened(IProject project) { + // nothing to do. + } + + /* + * Does nothing + * (non-Javadoc) + * @see com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IProjectListener#projectOpenedWithWorkspace(org.eclipse.core.resources.IProject) + */ + public void projectOpenedWithWorkspace(IProject project) { + // nothing to do. + } +} From 2f1d5e3425bf4a530fc74d0c0c1448fd97547b8f Mon Sep 17 00:00:00 2001 From: Amith Yamasani <> Date: Mon, 30 Mar 2009 07:28:42 -0700 Subject: [PATCH 06/45] AI 143472: Reduce dictionary size. Changed the tree structure to have variable length nodes to save an average of 21% on the dictionary size. Created a shortened English dictionary for Dream - 50K words. Added a shortened Spanish dictionary for Dream - 32K words. BUG=1743626 Automated import of CL 143472 --- .../tools/dict/MakeBinaryDictionary.java | 100 ++++++++++++------ 1 file changed, 67 insertions(+), 33 deletions(-) diff --git a/tools/makedict/src/com/android/tools/dict/MakeBinaryDictionary.java b/tools/makedict/src/com/android/tools/dict/MakeBinaryDictionary.java index cbe702872..8a8a677da 100755 --- a/tools/makedict/src/com/android/tools/dict/MakeBinaryDictionary.java +++ b/tools/makedict/src/com/android/tools/dict/MakeBinaryDictionary.java @@ -45,6 +45,10 @@ public class MakeBinaryDictionary { public static final String TAG_WORD = "w"; public static final String ATTR_FREQ = "f"; + private static final int FLAG_ADDRESS_MASK = 0x400000; + private static final int FLAG_TERMINAL_MASK = 0x800000; + private static final int ADDRESS_MASK = 0x3FFFFF; + public static final CharNode EMPTY_NODE = new CharNode(); List roots; @@ -179,7 +183,7 @@ public class MakeBinaryDictionary { parent.children.add(child); } child.data = data; - child.freq += occur; + if (child.freq == 0) child.freq = occur; if (word.length() > charAt + 1) { addWordRec(child, word, charAt + 1, occur); } else { @@ -195,56 +199,76 @@ public class MakeBinaryDictionary { static final int ADDR_WIDTH = 23; // Offset to children static final int FREQ_WIDTH_BYTES = 1; static final int COUNT_WIDTH_BYTES = 1; - static final int NODE_SIZE_BYTES = - (CHAR_WIDTH + FLAGS_WIDTH + ADDR_WIDTH) / 8 + FREQ_WIDTH_BYTES; private void addCount(int count) { dict[dictSize++] = (byte) (0xFF & count); } - /* TODO: Allow characters to be beyond the 0-255 range. This is required for some latin - language not currently supported */ private void addNode(CharNode node) { int charData = 0xFFFF & node.data; if (charData > 254) { - System.out.println("WARNING: Non-ASCII character encountered : " + node.data + - ", value = " + charData); - dict[dictSize++] = '@'; + dict[dictSize++] = (byte) 255; + dict[dictSize++] = (byte) ((node.data >> 8) & 0xFF); + dict[dictSize++] = (byte) (node.data & 0xFF); } else { dict[dictSize++] = (byte) (0xFF & node.data); } - dictSize += 3; // Space for children address - if ((0xFFFFFF & node.freq) > 255) { - node.freq = (byte) 255; + if (node.children != null) { + dictSize += 3; // Space for children address + } else { + dictSize += 1; // Space for just the terminal/address flags + } + if ((0xFFFFFF & node.freq) > 255) { + node.freq = 255; + } + if (node.terminal) { + byte freq = (byte) (0xFF & node.freq); + dict[dictSize++] = freq; } - dict[dictSize++] = (byte) (0xFF & node.freq); } + int nullChildrenCount = 0; + int notTerminalCount = 0; + private void updateNodeAddress(int nodeAddress, CharNode node, int childrenAddress) { - childrenAddress = 0x7FFFFF & childrenAddress; + if ((dict[nodeAddress] & 0xFF) == 0xFF) { // 3 byte character + nodeAddress += 2; + } + childrenAddress = ADDRESS_MASK & childrenAddress; + if (childrenAddress == 0) { + nullChildrenCount++; + } else { + childrenAddress |= FLAG_ADDRESS_MASK; + } if (node.terminal) { - childrenAddress |= 0x800000; + childrenAddress |= FLAG_TERMINAL_MASK; + } else { + notTerminalCount++; } dict[nodeAddress + 1] = (byte) (childrenAddress >> 16); - dict[nodeAddress + 2] = (byte) ((childrenAddress & 0xFF00) >> 8); - dict[nodeAddress + 3] = (byte) ((childrenAddress & 0xFF)); + if ((childrenAddress & FLAG_ADDRESS_MASK) != 0) { + dict[nodeAddress + 2] = (byte) ((childrenAddress & 0xFF00) >> 8); + dict[nodeAddress + 3] = (byte) ((childrenAddress & 0xFF)); + } } void writeWordsRec(List children) { if (children == null || children.size() == 0) { return; } - addCount(children.size()); - int childrenStart = dictSize; - for (int j = 0; j < children.size(); j++) { + final int childCount = children.size(); + addCount(childCount); + //int childrenStart = dictSize; + int[] childrenAddresses = new int[childCount]; + for (int j = 0; j < childCount; j++) { CharNode node = children.get(j); + childrenAddresses[j] = dictSize; addNode(node); } - for (int j = 0; j < children.size(); j++) { + for (int j = 0; j < childCount; j++) { CharNode node = children.get(j); - // TODO: Fix this when child length becomes variable - int nodeAddress = childrenStart + NODE_SIZE_BYTES * j; + int nodeAddress = childrenAddresses[j]; int cacheDictSize = dictSize; writeWordsRec(node.children); updateNodeAddress(nodeAddress, node, node.children != null @@ -253,8 +277,8 @@ public class MakeBinaryDictionary { } void writeToDict(String dictFilename) { - // 2MB max - dict = new byte[2 * 1024 * 1024]; // 2MB upper limit. Actual is probably + // 4MB max, 22-bit offsets + dict = new byte[4 * 1024 * 1024]; // 4MB upper limit. Actual is probably // < 1MB in most cases, as there is a limit in the // resource size in apks. dictSize = 0; @@ -272,19 +296,29 @@ public class MakeBinaryDictionary { void traverseDict(int pos, char[] word, int depth) { int count = dict[pos++] & 0xFF; for (int i = 0; i < count; i++) { - char c = (char) (dict[pos] & 0xFF); - word[depth] = c; - if ((dict[pos + 1] & 0x80) > 0) { - showWord(word, depth + 1, dict[pos + 4] & 0xFF); + char c = (char) (dict[pos++] & 0xFF); + if (c == 0xFF) { + c = (char) (((dict[pos] & 0xFF) << 8) | (dict[pos+1] & 0xFF)); + pos += 2; + } + word[depth] = c; + boolean terminal = (dict[pos] & 0x80) > 0; + int address = 0; + if ((dict[pos] & (FLAG_ADDRESS_MASK >> 16)) > 0) { + address = + ((dict[pos + 0] & (FLAG_ADDRESS_MASK >> 16)) << 16) + | ((dict[pos + 1] & 0xFF) << 8) + | ((dict[pos + 2] & 0xFF)); + pos += 2; + } + pos++; + if (terminal) { + showWord(word, depth + 1, dict[pos] & 0xFF); + pos++; } - int address = - ((dict[pos + 1] & 0x7F) << 16) - | ((dict[pos + 2] & 0xFF) << 8) - | ((dict[pos + 3] & 0xFF)); if (address != 0) { traverseDict(address, word, depth + 1); } - pos += NODE_SIZE_BYTES; } } From b2cb5fd2ebbf30560a9edf12a2a5f67aeaf888c9 Mon Sep 17 00:00:00 2001 From: Raphael Moll <> Date: Mon, 30 Mar 2009 11:27:15 -0700 Subject: [PATCH 07/45] AI 143491: ADT #1742875: Document the SDK build process and new cupcake SDK changes. BUG=1742875 Automated import of CL 143491 --- docs/howto_build_SDK.txt | 280 +++++++++++++++++++++++++ docs/howto_use_cupcake_sdk.txt | 371 +++++++++++++++++++++++++++++++++ 2 files changed, 651 insertions(+) create mode 100644 docs/howto_build_SDK.txt create mode 100644 docs/howto_use_cupcake_sdk.txt diff --git a/docs/howto_build_SDK.txt b/docs/howto_build_SDK.txt new file mode 100644 index 000000000..4b6507d4a --- /dev/null +++ b/docs/howto_build_SDK.txt @@ -0,0 +1,280 @@ +Subject: How to build an Android SDK & ADT Eclipse plugin. +Date: 2009/03/27 + + +Table of content: + 0- License + 1- Foreword + 2- Building an SDK for MacOS and Linux + 3- Building an SDK for Windows + 4- Building an ADT plugin for Eclipse + 5- Conclusion + + + +---------- +0- License +---------- + + Copyright (C) 2009 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. + + + +----------- +1- Foreword +----------- + +This document explains how to build the Android SDK and the ADT Eclipse plugin. + +It is designed for advanced users which are proficient with command-line +operations and know how to setup the pre-required software. + +Basically it's not trivial yet when done right it's not that complicated. + + + +-------------------------------------- +2- Building an SDK for MacOS and Linux +-------------------------------------- + +First, setup your development environment and get the Android source code from +git as explained here: + + http://source.android.com/download + +For example for the cupcake branch: + + $ mkdir ~/my-android-git + $ cd ~/my-android-git + $ repo init -u git://android.git.kernel.org/platform/manifest.git -b cupcake + $ repo sync + +Then once you have all the source, simply build the SDK using: + + $ cd ~/my-android-git + $ . build/envsetup.sh + $ make sdk + +This will take a while, maybe between 20 minutes and several hours depending on +your machine. After a while you'll see this in the output: + + Package SDK: out/host/darwin-x86/sdk/android-sdk_eng._mac-x86.zip + +Some options: + +- Depending on your machine you can tell 'make' to build more things in + parallel, e.g. if you have a dual core, use "make -j4 sdk" to build faster. + +- You can define "BUILD_NUMBER" to control the build identifier that gets + incorporated in the resulting archive. The default is to use your username. + One suggestion is to include the date, e.g.: + + $ export BUILD_NUMBER=${USER}-`date +%Y%m%d-%H%M%S` + + There are certain characters you should avoid in the build number, typically + everything that might confuse 'make' or your shell. So for example avoid + punctuation and characters like $ & : / \ < > , and . + + + +------------------------------ +3- Building an SDK for Windows +------------------------------ + +A- SDK pre-requisite +-------------------- + +First you need to build an SDK for MacOS and Linux. The Windows build works by +updating an existing MacOS or Linux SDK zip file and replacing the unix +binaries by Windows binaries. + + + +B- Cygwin pre-requisite & code checkout +--------------------------------------- + +Second you need to install Cygwin and configure it: +- Get the installer at http://sources.redhat.com/cygwin/ +- When installing Cygwin, set Default Text File Type to Unix/binary, not DOS/text. + This is really important, otherwise you will get errors when trying to + checkout code using git. +- Packages that you must install or not: + - Required packages: autoconf, bison, curl, flex, gcc, g++, git, gnupg, make, + mingw-zlib, python, zip, unzip. + - Suggested extra packages: diffutils, emacs, openssh, rsync, vim, wget. + - Packages that must not be installed: readline. + +Once you installed Cygwin properly, checkout the code from git as you did +for MacOS or Linux. Make sure to get the same branch, and if possible keep +it as close to the other one as possible: + + $ mkdir ~/my-android-git + $ cd ~/my-android-git + $ repo init -u git://android.git.kernel.org/platform/manifest.git -b cupcake + $ repo sync + + + +C- Building the Windows SDK +--------------------------- + +Now it's time to build that Windows SDK. You need: +- The path to the MacOS or Linux SDK zip. +- A directory where to place the final SDK. It will also hold some temporary + files. +- The build number will be extracted from the SDK zip filename, but this will + only work if that build number has no underscores in it. It is suggested you + just define SDK_NUMBER (and not BUILD_NUMBER!) on the command line before + invoking the script. + + Note that the "SDK number" is really a free identifier of your choice. It + doesn't need to be strictly a number. As always it is suggested you avoid + too much punctuation and special shell/make characters. Underscores cannot + be used. + + +To summarize, the steps on the command line would be something like this: + + $ mkdir ~/mysdk + $ export SDK_NUMBER=${USER}-`date +%Y%m%d-%H%M%S` + $ cd ~/my-android-git + $ development/build/tools/make_windows_sdk.sh /path/to/macos/or/linux/sdk.zip ~/mysdk + +This will take a while to build some Windows-specific binaries, including the +emulator, unzip the previous zip, rename & replace things and rezip the final +Windows SDK zip file. A typical build time should be around 5-10 minutes. + + + +------------------------------------- +4- Building an ADT plugin for Eclipse +------------------------------------- + +Requirements: +- You can currently only build an ADT plugin for Eclipse under Linux. +- You must have a working version of Eclipse 3.4 "ganymede" RCP installed. +- You need X11 to run Eclipse at least once. +- You need a lot of patience. The trick is to do the initial setup correctly + once, after it's a piece of cake. + + + +A- Pre-requisites +----------------- + +Note for Ubuntu or Debian users: your apt repository probably only has Eclipse +3.2 available and it's probably not suitable to build plugins in the first +place. Forget that and install a working 3.4 manually as described below. + +- Visit http://www.eclipse.org/downloads/ to grab the + "Eclipse for RCP/Plug-in Developers (176 MB)" download for Linux. + 32-bit and 64-bit versions are available, depending on your Linux installation. + + Note: we've always used a 32-bit one, so use the 64-bit one at your own risk. + + Note: Eclipse comes in various editions. Do yourself a favor and just stick + to the RCP for building this plugin. For example the J2EE contains too many + useless features that will get in the way, and the "Java" version lacks some + plugins you need to build other plugins. Please just use the RCP one. + +- Unpack "eclipse-rcp-ganymede-SR2-linux-gtk.tar.gz" in the directory of + your choice, e.g.: + + $ mkdir ~/eclipse-3.4 + $ cd ~/eclipse-3.4 + $ tar xvzf eclipse-rcp-ganymede-SR2-linux-gtk.tar.gz + + This will create an "eclipse" directory in the current directory. + +- Set ECLIPSE_HOME to that "eclipse" directory: + + $ export ECLIPSE_HOME=~/eclipse-3.4/eclipse + + Note: it is important you set ECLIPSE_HOME before starting the build. + Otherwise the build process will try to download and install its own Eclipse + installation in /buildroot, which is probably limited to root. + +- Now, before you can build anything, it is important that you start Eclipse + *manually* once using the same user that you will use to build later. That's + because your Eclipse installation is not finished: Eclipse must be run at + least once to create some files in ~/.eclipse/. So run Eclipse now: + + $ ~/eclipse-3.4/eclipse/eclipse & + + Wait for it load, create a workspace when requested and then simply quit + using the File > Quit menu. That's it. You won't need to run it manually + again. + + + +B- Building ADT +--------------- + +Finally, you have Eclipse, it's installed and it created its own config files, +so now you can build your ADT plugin. To do that you'll change directories to +your git repository and invoke the build script by giving it a destination +directory and an optional build number: + + $ mkdir ~/mysdk + $ cd ~/my-android-git # <-- this is where you did your "repo sync" + $ development/tools/eclipse/scripts/build_server.sh ~/mysdk $USER + +The first argument is the destination directory. It must be absolute. Do not +give a relative destination directory such as "../mysdk". This will make the +Eclipse build fail with a cryptic message: + + BUILD SUCCESSFUL + Total time: 1 minute 5 seconds + **** Package in ../mysdk + Error: Build failed to produce ../mysdk/android-eclipse + Aborting + +The second argument is the build "number". The example used "$USER" but it +really is a free identifier of your choice. It cannot contain spaces nor +periods (dashes are ok.) If the build number is missing, a build timestamp will +be used instead in the filename. + +The build should take something like 5-10 minutes. + + +When the build succeeds, you'll see something like this at the end of the +output: + + ZIP of Update site available at ~/mysdk/android-eclipse-v200903272328.zip +or + ZIP of Update site available at ~/mysdk/android-eclipse-.zip + +When you load the plugin in Eclipse, its feature and plugin name will look like +"com.android.ide.eclipse.adt_0.9.0.v200903272328-.jar". The +internal plugin ID is always composed of the package, the build timestamp and +then your own build identifier (a.k.a. the "build number"), if provided. This +means successive builds with the same build identifier are incremental and +Eclipse will know how to update to more recent ones. + + + +------------- +5- Conclusion +------------- + +This completes the howto guide on building your own SDK and ADT plugin. +Feedback is welcome on the public Android Open Source forums: + http://source.android.com/discuss + +If you are upgrading from a pre-cupcake to a cupcake or later SDK please read +the accompanying document "howto_use_cupcake_sdk.txt". + +-end- + diff --git a/docs/howto_use_cupcake_sdk.txt b/docs/howto_use_cupcake_sdk.txt new file mode 100644 index 000000000..b13123043 --- /dev/null +++ b/docs/howto_use_cupcake_sdk.txt @@ -0,0 +1,371 @@ +Subject: How to build use a Cupcake Android SDK & ADT Eclipse plugin. +Date: 2009/03/27 + + +Table of content: + 0- License + 1- Foreword + 2- Installation steps + 3- For Eclipse users + 4- For Ant users + 5- Targets, AVDs, Emulator changes + 6- Conclusion + + + +---------- +0- License +---------- + + Copyright (C) 2009 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. + + + +----------- +1- Foreword +----------- + +This explains how to use the "new" SDK provided starting with cupcake. +The new SDK has as a different structure than the pre-cupcake ones. + +This means: +- The new SDK does not work with older Eclipse plugins (ADT 0.8) +- The old SDKs (1.0 and 1.1) do NOT work with this Eclipse plugin (ADT 0.9) + + + +---------------------- +2- Installation steps +---------------------- + +First you will need to grab the zip of the SDK for your platform or build it +yourself. Please refer to the accompanying document "howto_build_SDK.txt" if +needed. + +Unzip the SDK somewhere. We'll call that directory "SDK" in command-line +examples. + +Grab the new ADT Eclipse plugin zip file or build it yourself. Keep it +somewhere (no need to unzip). + + + +-------------------- +3- For Eclipse users +-------------------- + + +Below we'll explain how you can upgrade your Eclipse install to the new plugin. +If you already have a working Eclipse installation with a pre-0.9 ADT, +another suggestion is to simply install a new copy of Eclipse and create a +new empty workspace. This is just a precaution. The update process should +be otherwise harmless. + + + +A- Setting up Eclipse +--------------------- + +- You must have Eclipse 3.3 or 3.4. Eclipse 3.2 is not longer supported. + + There are many flavors, or "editions", of Eclipse. To develop, we'd recommend + the "Java" edition. The "RCP" one is totally suitable too. The J2EE one is + probably overkill. + + +- If updating an existing Eclipse, use Help > Software Update and please + uninstall the two features of the previous ADT: the "editors" feature and the + ADT feature itself. + + => If you don't you will get a conflict on editors when installing + the new one. + +- Using Help > Software Update, add a new "archived site", point it to the new + adt.zip (e.g. android-eclipse-.zip), select the "Install" button at + the top right and restart eclipse as needed. + +- After it restarts, please use Window > Preferences > Android and select + the new SDK folder that you unzipped in paragraph 2. + + + +B- Updating older projects +-------------------------- + +If you have pre-0.9 projects in your Eclipse workspace, or if you import them +from your code repository, these projects will fail to build at first. + +First right-click on the project and select "Properties": + +- In the properties, open the Android panel and select the platform to use. + The SDK comes with a 1.5 platform. Select it and close the properties panel. +- Do a clean build. + + +The new plugin creates a "gen" folder in your project where it puts the R.java +and all automatically generated AIDL java files. If you get an error such as: + + "The type R is already defined" + +that means you must check to see if your old R.java or your old auto-generated +AIDL Java files are still present in the "src" folder. If yes, remove them. + +Note: this does not apply to your own hand-crafted parcelable AIDL java files. + +Note: if you want to reuse the project with an older Eclipse ADT install, + simply remove the "gen" folder from the build path of the project. + + +C- New Wizards +-------------- + +The "New Android Project" wizard has been expanded to use the multi-platform +capabilities of the new SDK. + +There is now a "New XML File" wizard that lets you create skeleton XML resource +files for your Android projects. This makes it easier to create a new layout, a +new strings file, etc. + +Both wizard are available via File > New... as well as new icons in the main +icon bar. If you do not see the new icons, you may need to use Window > Reset +Perspective on your Java perspective. + + +Please see step 5 "Emulator changes" below for important details on how to run +the emulator. + + + +---------------- +4- For Ant users +---------------- + + +A- build.xml has changed +------------------------ + +You must re-create your build.xml file. + +First if you had customized your build.xml, make a copy of it: + + $ cd my-project + $ cp build.xml build.xml.old + + +Then use the new "android" tool to create a new build.xml: + + $ SDK/tools/android update project --path /path/to/my-project + +or + + $ cd my-project + $ SDK/tools/android update project --path . + + +A "gen" folder will be created the first time you build and your R.java and +your AIDL Java files will be generated in this "gen" folder. You MUST remove +the old R.java and old auto-generated AIDL java files manually. (Note: this +does not apply to your own hand-crafted parcelabe AIDL java files.) + + +B- Where is activitycreator? +---------------------------- + +Note that the "activitycreator" tool has been replaced by the new "android" +tool too. Example of how to create a new Ant project: + + $ SDK/tools/android create project --path /path/to/my/project --name ProjectName + --package com.mycompany.myapp --activity MyActivityClass + --target 1 --mode activity + + +Please see paragraph 5 below for important details on how to run the emulator +and the meaning of that "--target 1" parameter. + + + +---------------------------------- +5- Targets, AVDs, Emulator changes +---------------------------------- + +This applies to BOTH Eclipse and Ant users. + +One major change with the emulator is that now you must pre-create an "Android +Virtual Device" (a.k.a "AVD") before you run the emulator. + + + +A- What is an AVD and why do I need one? +---------------------------------------- + +What is an "AVD"? If you forget, just run: + + $ SDK/tools/emulator -help-virtual-device + + An Android Virtual Device (AVD) models a single virtual device running the + Android platform that has, at least, its own kernel, system image and data + partition. + +There is a lot more explanation given by the emulator. Please run the help +command given above to read the rest. + +The bottom line is that you can create many emulator configurations, or "AVDs", +each with their own system image and most important each with their own user +data and SD card data. Then you tell Eclipse or the emulator which one to use +to debug or run your applications. + + +Note for Eclipse users: eventually there will be a user interface to do all of +these operations. For right now, please use the command line interface. + + +B- Listing targets and AVDs +--------------------------- + +There is a new tool called "android" in the SDK that lets you know which +"target" and AVDs you can use. + +A target is a specific version of Android that you can use. By default the SDK +comes with an "Android 1.5" target, codenamed "cupcake". In the future there +will be more versions of Android to use, e.g. "Android 2.0" or specific add-ons +provided by hardware manufacturers. When you want to run an emulator, you need +to specify a given flavor of Android: this is the "target". + + +To learn about available targets in your SDK, use this command: + + $ SDK/tools/android list targets + +This will give you an output such as: + + Available Android targets: + [1] Android 1.5 + API level: 3 + Skins: HVGA (default), HVGA-L, HVGA-P, QVGA-L, QVGA-P + +Note the "[1]". Later you will need to reference this as "--target 1" on the +command line. + + +Similarly you can list the available AVDs: + + $ SDK/tools/android list avds + +Which might output something as: + + Available Android Virtual Devices: + Name: my_avd + Path: C:\Users\\.android\avd\my_avd.avd + Target: Android 1.5 (API level 3) + Skin: 320x480 + Sdcard: 16M + + + +C- Creating an AVD +------------------ + +To create a configuration: + + $ SDK/tools/android create avd --name my_avd_name --target 1 + + +where "target 1" is the index of a target listed by "android list targets". + +The AVD name is purely an identifier used to refer to the AVD later. +Since it is used as directory name, please avoid using shell or path specific +characters. + +To learn the various options available when creating an AVD, simply type: + + $ SDK/tools/android create avd + +The android tool will automatically print an explanation of required arguments. + + + +D- Invoking an AVD from the command-line +---------------------------------------- + +To use this AVD in the emulator from the command-line, type: + + $ SDK/tools/emulator @my_avd_name + + +For more options, please consult the emulator help: + + $ SDK/tools/emulator -help-virtual-device + + + +E- Invoking an AVD from Eclipse +------------------------------- + +By default Android projects in Eclipse have an "automatic target" mode. +In this mode, when a project is deployed in debug or run, it checks: +- If there's one running device or emulator, this is used for deployment. +- If there's more than one running device or emulator, a "device chooser" is + shown to let the user select which one to use. +- If there are no running devices or emulators, ADT looks at available AVDs. + If one matches the project configuration (e.g. same API level), it is + automatically used. + +Alternatively you can edit the "launch configuration" on your Android project +in Eclipse by selecting the menu Run > Run Configurations. In the "target" tab +of the configuration, you can choose: + +- Manual or automatic targetting mode. + + - Manual means to always present the device chooser. + - Automatic is the behavior explained above. + +- In automatic mode, which AVD is preferred. If none is selected, the first + suitable is used. + + +F- AVD concurrency +------------------ + +You can no longer run several emulators at the same time on the same +configuration. + +Before this used to put the second or more emulators in a transient read-only +mode that would not save user data. + +Now you just need to create as many AVDs as you want to run emulators. + +For example if you are working on a client/server application for Android, you +could create a "client" AVD and a "server" AVD then run them both at once. The +emulator window will show you the AVD name so that you know which one is which. + +Example: + + $ SDK/tools/android create avd --name client --target 1 --sdcard 16M --skin HVGA + $ SDK/tools/android create avd --name server --target 1 --sdcard 32M --skin HVGA-P + $ SDK/tools/emulator @server & + $ SDK/tools/emulator @client & + + + +------------- +6- Conclusion +------------- + +This completes the howto guide on how to use the new Cupcake SDK. +Feedback is welcome on the public Android Open Source forums: + http://source.android.com/discuss + +-end- + From 9738144670ebf492541b0c645418c1a8e744bb1a Mon Sep 17 00:00:00 2001 From: Xavier Ducrohet <> Date: Mon, 30 Mar 2009 12:31:27 -0700 Subject: [PATCH 08/45] AI 143499: Fix the icon for the JUnit launch shortcut BUG=866690 Automated import of CL 143499 --- tools/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml b/tools/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml index 2c1394cd2..a75b8b915 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml @@ -551,7 +551,7 @@ point="org.eclipse.debug.ui.launchShortcuts"> From f7dd570dec9e6ceca93119f01cb583589533c940 Mon Sep 17 00:00:00 2001 From: Brett Chabot <> Date: Mon, 30 Mar 2009 17:00:24 -0700 Subject: [PATCH 09/45] AI 143562: Usability fixes for runtest.py BUG=1743678 Automated import of CL 143562 --- testrunner/adb_interface.py | 23 +++++++++++++++++------ testrunner/coverage.py | 21 +++++++++++++++++++++ testrunner/logger.py | 17 ++++++++++++++--- testrunner/runtest.py | 16 ++++++++++++++-- 4 files changed, 66 insertions(+), 11 deletions(-) diff --git a/testrunner/adb_interface.py b/testrunner/adb_interface.py index fb304df9d..ad1b2c94f 100755 --- a/testrunner/adb_interface.py +++ b/testrunner/adb_interface.py @@ -297,8 +297,7 @@ class AdbInterface: WaitForResponseTimedOutError if wait_time elapses and pm still does not respond. """ - logger.Log("Waiting for device package manager for %s seconds..." - % wait_time) + logger.Log("Waiting for device package manager...") self.SendCommand("wait-for-device") # Now the device is there, but may not be running. # Query the package manager with a basic command @@ -315,7 +314,8 @@ class AdbInterface: time.sleep(wait_period) attempts += 1 if not pm_found: - raise errors.WaitForResponseTimedOutError + raise errors.WaitForResponseTimedOutError( + "Package manager did not respond after %s seconds" % wait_time) def Sync(self, retry_count=3): """Perform a adb sync. @@ -331,13 +331,12 @@ class AdbInterface: output = self.SendCommand("sync", retry_count=retry_count) if "Read-only file system" in output: logger.SilentLog(output) - logger.Log("adb sync failed due to read only fs, retrying") + logger.Log("Remounting read-only filesystem") self.SendCommand("remount") output = self.SendCommand("sync", retry_count=retry_count) if "No space left on device" in output: logger.SilentLog(output) - logger.Log("adb sync failed due to no space on device, trying shell" + - " start/stop") + logger.Log("Restarting device runtime") self.SendShellCommand("stop", retry_count=retry_count) output = self.SendCommand("sync", retry_count=retry_count) self.SendShellCommand("start", retry_count=retry_count) @@ -345,3 +344,15 @@ class AdbInterface: logger.SilentLog(output) self.WaitForDevicePm() return output + + def IsDevicePresent(self): + """Check if targeted device is present. + + Returns: + True if device is present, False otherwise. + """ + output = self.SendShellCommand("ls", retry_count=0) + if output.startswith("error:"): + return False + else: + return True diff --git a/testrunner/coverage.py b/testrunner/coverage.py index 507c5c79d..39a2ceb21 100755 --- a/testrunner/coverage.py +++ b/testrunner/coverage.py @@ -70,6 +70,27 @@ class CoverageGenerator(object): def EnableCoverageBuild(self): """Enable building an Android target with code coverage instrumentation.""" os.environ[self._EMMA_BUILD_FLAG] = "true" + #TODO: can emma.jar automagically be added to bootclasspath here? + + def TestDeviceCoverageSupport(self): + """Check if device has support for generating code coverage metrics. + + Currently this will check if the emma.jar file is on the device's boot + classpath. + + Returns: + True if device can support code coverage. False otherwise. + """ + output = self._adb.SendShellCommand("cat init.rc | grep BOOTCLASSPATH | " + "grep emma.jar") + if len(output) > 0: + return True + else: + logger.Log("Error: Targeted device does not have emma.jar on its " + "BOOTCLASSPATH.") + logger.Log("Modify the BOOTCLASSPATH entry in system/core/rootdir/init.rc" + " to add emma.jar") + return False def ExtractReport(self, test_suite, device_coverage_path=_DEVICE_COVERAGE_PATH, diff --git a/testrunner/logger.py b/testrunner/logger.py index 762c89311..61463a198 100755 --- a/testrunner/logger.py +++ b/testrunner/logger.py @@ -25,6 +25,7 @@ import datetime _LOG_FILE = None _verbose = False +_log_time = True def Init(log_file_path): """Set the path to the log file""" @@ -57,8 +58,13 @@ def _WriteLog(msg): def _PrependTimeStamp(log_string): """Returns the log_string prepended with current timestamp """ - return "# %s: %s" % (datetime.datetime.now().strftime("%m/%d/%y %H:%M:%S"), - log_string) + global _log_time + if _log_time: + return "# %s: %s" % (datetime.datetime.now().strftime("%m/%d/%y %H:%M:%S"), + log_string) + else: + # timestamp logging disabled + return log_string def SilentLog(new_str): """Silently log new_str. Unless verbose mode is enabled, will log new_str @@ -77,7 +83,12 @@ def SetVerbose(new_verbose=True): """ Enable or disable verbose logging""" global _verbose _verbose = new_verbose - + +def SetTimestampLogging(new_timestamp=True): + """ Enable or disable outputting a timestamp with each log entry""" + global _log_time + _log_time = new_timestamp + def main(): pass diff --git a/testrunner/runtest.py b/testrunner/runtest.py index bf5bb2232..a4df95034 100755 --- a/testrunner/runtest.py +++ b/testrunner/runtest.py @@ -53,6 +53,10 @@ class TestRunner(object): "The runtest script works in two ways. You can query it " "for a list of tests, or you can launch one or more tests.") + def __init__(self): + # disable logging of timestamp + logger.SetTimestampLogging(False) + def _ProcessOptions(self): """Processes command-line options.""" # TODO error messages on once-only or mutually-exclusive options. @@ -178,10 +182,14 @@ class TestRunner(object): self._coverage_gen.EnableCoverageBuild() self._AddBuildTarget(self._coverage_gen.GetEmmaBuildPath(), target_set) target_build_string = " ".join(list(target_set)) - logger.Log("Building %s" % target_build_string) + logger.Log("mmm %s" % target_build_string) cmd = 'ONE_SHOT_MAKEFILE="%s" make -C "%s" files' % (target_build_string, self._root_path) - if not self._options.preview: + if self._options.preview: + # in preview mode, just display to the user what command would have been + # run + logger.Log("adb sync") + else: run_command.RunCommand(cmd, return_output=False) logger.Log("Syncing to device...") self._adb.Sync() @@ -259,6 +267,10 @@ class TestRunner(object): self._DumpTests() return + if not self._adb.IsDevicePresent(): + logger.Log("Error: specified device cannot be found") + return + if not self._options.skip_build: self._DoBuild() From 1a43129cfaf4a977151f70108edaaba552646074 Mon Sep 17 00:00:00 2001 From: Yu Shan Emily Lau <> Date: Mon, 30 Mar 2009 21:14:52 -0700 Subject: [PATCH 10/45] AI 143596: Removed all the obsoleted media related functional test suite. (incl, very old meidaProvider, RingToneSettings and the flaky Music Player test. BUG=1683748,1678380 Automated import of CL 143596 --- testrunner/tests.xml | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/testrunner/tests.xml b/testrunner/tests.xml index d186af4c7..7e13a35db 100644 --- a/testrunner/tests.xml +++ b/testrunner/tests.xml @@ -186,21 +186,6 @@ These attributes map to the following commands: package="com.android.mediaframeworktest" runner=".MediaFrameworkUnitTestRunner" coverage_target="framework" /> - - - - - - - From e529390a9c0f6a9076b99d09e9cc4ad23d7f525f Mon Sep 17 00:00:00 2001 From: Raphael Moll <> Date: Tue, 31 Mar 2009 12:39:09 -0700 Subject: [PATCH 11/45] AI 143754: SdkManager: list unknown AVDs and why they didn't load. BUG=1703143 Automated import of CL 143754 --- .../app/src/com/android/sdkmanager/Main.java | 21 +- .../com/android/sdklib/avd/AvdManager.java | 205 ++++++++++++++---- 2 files changed, 181 insertions(+), 45 deletions(-) diff --git a/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java b/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java index adf37ed0b..191aa9eda 100644 --- a/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java +++ b/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java @@ -459,11 +459,30 @@ class Main { mSdkLog.printf(" Sdcard: %s\n", sdcard); } } + + // Are there some unused AVDs? + List badAvds = avdManager.getUnavailableAvdList(); + + if (badAvds == null || badAvds.size() == 0) { + return; + } + + mSdkLog.printf("\nThe following Android Virtual Devices are no longer available:\n"); + boolean needSeparator = false; + for (AvdInfo info : badAvds) { + if (needSeparator) { + mSdkLog.printf("---------\n"); + } + mSdkLog.printf(" Name: %s\n", info.getName() == null ? "--" : info.getName()); + mSdkLog.printf(" Path: %s\n", info.getPath() == null ? "--" : info.getPath()); + mSdkLog.printf(" Error: %s\n", info.getError() == null ? "--" : info.getError()); + needSeparator = true; + } } catch (AndroidLocationException e) { errorAndExit(e.getMessage()); } } - + /** * Creates a new AVD. This is a text based creation with command line prompt. */ diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java index 93577e42b..4342551ec 100644 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java @@ -32,8 +32,11 @@ import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.TreeSet; import java.util.Map.Entry; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -118,15 +121,43 @@ public final class AvdManager { private final String mPath; private final IAndroidTarget mTarget; private final Map mProperties; - - /** Creates a new AVD info. Values are immutable. - * @param properties */ + private final String mError; + + /** + * Creates a new valid AVD info. Values are immutable. + *

+ * Such an AVD is available and can be used. + * The error string is set to null. + * + * @param name The name of the AVD (for display or reference) + * @param path The path to the config.ini file + * @param target The target. Cannot be null. + * @param properties The property map. Cannot be null. + */ public AvdInfo(String name, String path, IAndroidTarget target, Map properties) { + this(name, path, target, properties, null /*error*/); + } + + /** + * Creates a new invalid AVD info. Values are immutable. + *

+ * Such an AVD is not complete and cannot be used. + * The error string must be non-null. + * + * @param name The name of the AVD (for display or reference) + * @param path The path to the config.ini file + * @param target The target. Can be null. + * @param properties The property map. Can be null. + * @param error The error describing why this AVD is invalid. Cannot be null. + */ + public AvdInfo(String name, String path, IAndroidTarget target, + Map properties, String error) { mName = name; mPath = path; mTarget = target; mProperties = properties; + mError = error; } /** Returns the name of the AVD. */ @@ -144,6 +175,11 @@ public final class AvdManager { return mTarget; } + /** Returns the error describing why an AVD failed to load. Always null for valid AVDs. */ + public String getError() { + return mError; + } + /** * Helper method that returns the .ini {@link File} for a given AVD name. * @throws AndroidLocationException if there's a problem getting android root directory. @@ -634,29 +670,27 @@ public final class AvdManager { } } - private void buildAvdList(ArrayList list) throws AndroidLocationException { + /** + * Returns a list of files that are potential AVD ini files. + *

+ * This lists the $HOME/.android/avd/.ini files. + * Such files are properties file than then indicate where the AVD folder is located. + * + * @return A new {@link File} array or null. The array might be empty. + * @throws AndroidLocationException if there's a problem getting android root directory. + */ + private File[] buildAvdFilesList() throws AndroidLocationException { // get the Android prefs location. String avdRoot = AndroidLocation.getFolder() + AndroidLocation.FOLDER_AVD; - final boolean avdListDebug = System.getenv("AVD_LIST_DEBUG") != null; - if (avdListDebug) { - mSdkLog.printf("[AVD LIST DEBUG] AVD root: '%s'\n", avdRoot); - } - // ensure folder validity. File folder = new File(avdRoot); if (folder.isFile()) { - if (avdListDebug) { - mSdkLog.printf("[AVD LIST DEBUG] AVD root is a file.\n"); - } throw new AndroidLocationException(String.format("%s is not a valid folder.", avdRoot)); } else if (folder.exists() == false) { - if (avdListDebug) { - mSdkLog.printf("[AVD LIST DEBUG] AVD root folder doesn't exist, creating.\n"); - } // folder is not there, we create it and return folder.mkdirs(); - return; + return null; } File[] avds = folder.listFiles(new FilenameFilter() { @@ -664,10 +698,6 @@ public final class AvdManager { if (INI_NAME_PATTERN.matcher(name).matches()) { // check it's a file and not a folder boolean isFile = new File(parent, name).isFile(); - if (avdListDebug) { - mSdkLog.printf("[AVD LIST DEBUG] Item '%s': %s\n", - name, isFile ? "accepted file" : "rejected"); - } return isFile; } @@ -675,52 +705,130 @@ public final class AvdManager { } }); + return avds; + } + + /** + * Computes the internal list of available AVDs. + * This only contains AVDs that reference the target currently available. + * + * @param list An array list that will contain the list of AVDs. + * @throws AndroidLocationException if there's a problem getting android root directory. + */ + private void buildAvdList(ArrayList list) throws AndroidLocationException { + + File[] avds = buildAvdFilesList(); + for (File avd : avds) { - AvdInfo info = parseAvdInfo(avd); + AvdInfo info = parseAvdInfo(avd, false /*acceptError*/); if (info != null) { list.add(info); - if (avdListDebug) { - mSdkLog.printf("[AVD LIST DEBUG] Added AVD '%s'\n", info.getPath()); - } - } else if (avdListDebug) { - mSdkLog.printf("[AVD LIST DEBUG] Failed to parse AVD '%s'\n", avd.getPath()); } } } - - private AvdInfo parseAvdInfo(File path) { - Map map = SdkManager.parsePropertyFile(path, mSdkLog); + + public List getUnavailableAvdList() throws AndroidLocationException { + AvdInfo[] avds = getAvds(); + File[] allAvds = buildAvdFilesList(); + if (allAvds == null || allAvds.length == 0) { + return null; + } + + TreeSet list = new TreeSet(Arrays.asList(allAvds)); + + for (AvdInfo info : avds) { + if (list.remove(info.getIniFile())) { + if (list.size() == 0) { + return null; + } + } + } + ArrayList errorAvds = new ArrayList(list.size()); + for (File file : list) { + errorAvds.add(parseAvdInfo(file, true /*acceptError*/)); + } + + return errorAvds; + } + + /** + * Parses an AVD config.ini to create an {@link AvdInfo}. + * + * @param path The path to the AVD config.ini + * @param acceptError When false, an AVD that fails to load will be discarded and null will be + * returned. When true, such an AVD will be returned with an error description. + * @return A new {@link AvdInfo} or null if the file is not valid or null if the AVD is not + * valid and acceptError is false. + */ + private AvdInfo parseAvdInfo(File path, boolean acceptError) { + String error = null; + Map map = SdkManager.parsePropertyFile(path, mSdkLog); + String avdPath = map.get(AVD_INFO_PATH); - if (avdPath == null) { - return null; - } - String targetHash = map.get(AVD_INFO_TARGET); - if (targetHash == null) { - return null; + + IAndroidTarget target = null; + File configIniFile = null; + Map properties = null; + + if (targetHash != null) { + target = mSdk.getTargetFromHashString(targetHash); } - IAndroidTarget target = mSdk.getTargetFromHashString(targetHash); - if (target == null) { - return null; + // load the avd properties. + if (avdPath != null) { + configIniFile = new File(avdPath, CONFIG_INI); } - // load the avd properties. - File configIniFile = new File(avdPath, CONFIG_INI); - Map properties = SdkManager.parsePropertyFile(configIniFile, mSdkLog); + if (configIniFile != null) { + properties = SdkManager.parsePropertyFile(configIniFile, mSdkLog); + } + // get name + String name = path.getName(); Matcher matcher = INI_NAME_PATTERN.matcher(path.getName()); - + if (matcher.matches()) { + name = matcher.group(1); + } + + if (!acceptError) { + if (avdPath == null || + targetHash == null || + target == null || + configIniFile == null || + properties == null) { + return null; + } + } else { + if (avdPath == null || configIniFile == null) { + error = String.format("Missing AVD 'path' property in %1$s", name); + } else if (targetHash == null) { + error = String.format("Missing 'target' property in %1$s", name); + } else if (target == null) { + error = String.format("Unknown 'target=%2$s' property in %1$s", name, targetHash); + } else if (properties == null) { + error = String.format("Failed to parse properties from %1$s", avdPath); + } + } + AvdInfo info = new AvdInfo( - matcher.matches() ? matcher.group(1) : path.getName(), // should not happen + name, avdPath, target, - properties); + properties, + error); return info; } + /** + * Writes a new AVD config.ini file from a set of properties. + * + * @param iniFile The file to generate. + * @param values THe properties to place in the ini file. + * @throws IOException if {@link FileWriter} fails to open, write or close the file. + */ private static void createConfigIni(File iniFile, Map values) throws IOException { FileWriter writer = new FileWriter(iniFile); @@ -732,6 +840,15 @@ public final class AvdManager { } + /** + * Invokes the tool to create a new SD card image file. + * + * @param toolLocation The path to the mksdcard tool. + * @param size The size of the new SD Card, compatible with {@link #SDCARD_SIZE_PATTERN}. + * @param location The path of the new sdcard image file to generate. + * @param log The logger object, to report errors. + * @return True if the sdcard could be created. + */ private boolean createSdCard(String toolLocation, String size, String location, ISdkLog log) { try { String[] command = new String[3]; From a1ca267d261929253b97031407959bfb01a5a1b8 Mon Sep 17 00:00:00 2001 From: Brett Chabot <> Date: Tue, 31 Mar 2009 13:35:13 -0700 Subject: [PATCH 12/45] AI 143765: Rename tests.xml to test_defs.xml BUG=1746304 Automated import of CL 143765 --- testrunner/Android.mk | 2 +- testrunner/runtest.py | 8 ++++---- testrunner/{tests.xml => test_defs.xml} | 24 ++++++++++++++++++++++++ 3 files changed, 29 insertions(+), 5 deletions(-) rename testrunner/{tests.xml => test_defs.xml} (91%) diff --git a/testrunner/Android.mk b/testrunner/Android.mk index 93c092841..b6bde553b 100644 --- a/testrunner/Android.mk +++ b/testrunner/Android.mk @@ -10,7 +10,7 @@ LOCAL_PATH := $(call my-dir) ######################## include $(CLEAR_VARS) -LOCAL_MODULE := tests.xml +LOCAL_MODULE := test_defs.xml LOCAL_MODULE_TAGS := tests LOCAL_MODULE_CLASS := ETC LOCAL_MODULE_PATH := $(local_target_dir) diff --git a/testrunner/runtest.py b/testrunner/runtest.py index a4df95034..8d3659130 100755 --- a/testrunner/runtest.py +++ b/testrunner/runtest.py @@ -41,12 +41,12 @@ class TestRunner(object): # file path to android core platform tests, relative to android build root # TODO move these test data files to another directory - _CORE_TEST_PATH = os.path.join("development", "testrunner", "tests.xml") + _CORE_TEST_PATH = os.path.join("development", "testrunner", "test_defs.xml") # vendor glob file path patterns to tests, relative to android # build root _VENDOR_TEST_PATH = os.path.join("vendor", "*", "tests", "testinfo", - "tests.xml") + "test_defs.xml") _RUNTEST_USAGE = ( "usage: runtest.py [options] short-test-name[s]\n\n" @@ -61,7 +61,7 @@ class TestRunner(object): """Processes command-line options.""" # TODO error messages on once-only or mutually-exclusive options. user_test_default = os.path.join(os.environ.get("HOME"), ".android", - "tests.xml") + "test_defs.xml") parser = optparse.OptionParser(usage=self._RUNTEST_USAGE) @@ -153,7 +153,7 @@ class TestRunner(object): try: known_tests = test_defs.TestDefinitions() known_tests.Parse(core_test_path) - # read all /vendor/*/tests/testinfo/tests.xml paths + # read all /vendor/*/tests/testinfo/test_defs.xml paths vendor_tests_pattern = os.path.join(self._root_path, self._VENDOR_TEST_PATH) test_file_paths = glob.glob(vendor_tests_pattern) diff --git a/testrunner/tests.xml b/testrunner/test_defs.xml similarity index 91% rename from testrunner/tests.xml rename to testrunner/test_defs.xml index 7e13a35db..d186af4c7 100644 --- a/testrunner/tests.xml +++ b/testrunner/test_defs.xml @@ -186,6 +186,21 @@ These attributes map to the following commands: package="com.android.mediaframeworktest" runner=".MediaFrameworkUnitTestRunner" coverage_target="framework" /> + + + + + + + From e64360f76abbf50312c6fa8ca096a73dba698b4a Mon Sep 17 00:00:00 2001 From: Jeffrey Sharkey <> Date: Tue, 31 Mar 2009 16:55:19 -0700 Subject: [PATCH 13/45] AI 143864: Fix SDK example to correctly pass back newly-configured appWidgetId. BUG=1725041 Automated import of CL 143864 --- .../android/apis/appwidget/ExampleAppWidgetConfigure.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/samples/ApiDemos/src/com/example/android/apis/appwidget/ExampleAppWidgetConfigure.java b/samples/ApiDemos/src/com/example/android/apis/appwidget/ExampleAppWidgetConfigure.java index e0a4c76b0..d7ef9d632 100644 --- a/samples/ApiDemos/src/com/example/android/apis/appwidget/ExampleAppWidgetConfigure.java +++ b/samples/ApiDemos/src/com/example/android/apis/appwidget/ExampleAppWidgetConfigure.java @@ -89,7 +89,10 @@ public class ExampleAppWidgetConfigure extends Activity { saveTitlePref(ExampleAppWidgetConfigure.this, mAppWidgetId, mAppWidgetPrefix.getText().toString()); - setResult(RESULT_OK); + // Make sure we pass back the original appWidgetId + Intent resultValue = new Intent(); + resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId); + setResult(RESULT_OK, resultValue); finish(); } }; From 058dad6d77b7d218ec79b00d24bb355dc39db7b2 Mon Sep 17 00:00:00 2001 From: Raphael Moll <> Date: Tue, 31 Mar 2009 17:16:46 -0700 Subject: [PATCH 14/45] AI 143876: Include hprof-conv in SDK (bug #1640225) BUG=1640225 Automated import of CL 143876 --- build/sdk.atree | 1 + build/tools/make_windows_sdk.sh | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/build/sdk.atree b/build/sdk.atree index 0f62ea0bf..438ab77d8 100644 --- a/build/sdk.atree +++ b/build/sdk.atree @@ -24,6 +24,7 @@ bin/aidl platforms/${PLATFORM_NAME}/tools/aidl bin/adb tools/adb bin/sqlite3 tools/sqlite3 bin/dmtracedump tools/dmtracedump +bin/hprof-conv tools/hprof-conv bin/mksdcard tools/mksdcard # other tools diff --git a/build/tools/make_windows_sdk.sh b/build/tools/make_windows_sdk.sh index dedf3a785..2abe7b1f2 100755 --- a/build/tools/make_windows_sdk.sh +++ b/build/tools/make_windows_sdk.sh @@ -64,7 +64,8 @@ function build() { make -j 4 emulator || die "Build failed" # Disable parallel build: it generates "permission denied" issues when # multiple "ar.exe" are running in parallel. - make prebuilt adb fastboot aidl aapt dexdump dmtracedump mksdcard sqlite3 || die "Build failed" + make prebuilt adb fastboot aidl aapt dexdump dmtracedump hprof-conv mksdcard sqlite3 \ + || die "Build failed" } function package() { @@ -104,7 +105,7 @@ function package() { # Remove obsolete stuff from tools & platform TOOLS="$DEST/tools" LIB="$DEST/tools/lib" - rm -v "$TOOLS"/{adb,emulator,traceview,draw9patch,hierarchyviewer,apkbuilder,ddms,dmtracedump,mksdcard,sqlite3,android} + rm -v "$TOOLS"/{adb,emulator,traceview,draw9patch,hierarchyviewer,apkbuilder,ddms,dmtracedump,hprof-conv,mksdcard,sqlite3,android} rm -v --force "$LIB"/*.so "$LIB"/*.jnilib rm -v "$PLATFORM_TOOLS"/{aapt,aidl,dx,dexdump} From c01f497ad9967e7fb1e4148113555e3b5c9808f6 Mon Sep 17 00:00:00 2001 From: Raphael Moll <> Date: Tue, 31 Mar 2009 17:21:21 -0700 Subject: [PATCH 15/45] AI 143881: AVD #1703143: delete AVDs not loaded correctly. This covers the case where an AVD has an invalid target or is missing its AVD folder or the config.ini in it. Made some cosmetic cleanup too. BUG=1703143 Automated import of CL 143881 --- .../com/android/ide/eclipse/adt/sdk/Sdk.java | 4 +- .../app/src/com/android/sdkmanager/Main.java | 22 +++- .../src/com/android/sdklib/ISdkLog.java | 8 +- .../com/android/sdklib/avd/AvdManager.java | 103 ++++++++++++------ 4 files changed, 96 insertions(+), 41 deletions(-) diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/Sdk.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/Sdk.java index ba0b56803..40b3f76ec 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/Sdk.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/sdk/Sdk.java @@ -100,7 +100,7 @@ public class Sdk implements IProjectListener { ISdkLog log = new ISdkLog() { public void error(Throwable throwable, String errorFormat, Object... arg) { if (errorFormat != null) { - logMessages.add(String.format(errorFormat, arg)); + logMessages.add(String.format("Error: " + errorFormat, arg)); } if (throwable != null) { @@ -109,7 +109,7 @@ public class Sdk implements IProjectListener { } public void warning(String warningFormat, Object... arg) { - logMessages.add(String.format(warningFormat, arg)); + logMessages.add(String.format("Warning: " + warningFormat, arg)); } public void printf(String msgFormat, Object... arg) { diff --git a/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java b/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java index 191aa9eda..738640214 100644 --- a/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java +++ b/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java @@ -461,13 +461,13 @@ class Main { } // Are there some unused AVDs? - List badAvds = avdManager.getUnavailableAvdList(); + List badAvds = avdManager.getUnavailableAvds(); if (badAvds == null || badAvds.size() == 0) { return; } - mSdkLog.printf("\nThe following Android Virtual Devices are no longer available:\n"); + mSdkLog.printf("\nThe following Android Virtual Devices could not be loaded:\n"); boolean needSeparator = false; for (AvdInfo info : badAvds) { if (needSeparator) { @@ -592,7 +592,7 @@ class Main { File dir = new File(oldAvdInfo.getPath()); avdManager.recursiveDelete(dir); dir.delete(); - // Remove old avd info from manager + // Remove old AVD info from manager avdManager.removeAvd(oldAvdInfo); } @@ -602,13 +602,27 @@ class Main { } /** - * Delete an AVD. + * Delete an AVD. If the AVD name is not part of the available ones look for an + * invalid AVD (one not loaded due to some error) to remove it too. */ private void deleteAvd() { try { String avdName = mSdkCommandLine.getParamName(); AvdManager avdManager = new AvdManager(mSdkManager, mSdkLog); AvdInfo info = avdManager.getAvd(avdName); + + if (info == null) { + // Look in unavailable AVDs + List badAvds = avdManager.getUnavailableAvds(); + if (badAvds != null) { + for (AvdInfo i : badAvds) { + if (i.getName().equals(avdName)) { + info = i; + break; + } + } + } + } if (info == null) { errorAndExit("There is no Android Virtual Device named '%s'.", avdName); diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/ISdkLog.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/ISdkLog.java index 489451746..163f7a950 100644 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/ISdkLog.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/ISdkLog.java @@ -26,8 +26,10 @@ public interface ISdkLog { /** * Prints a warning message on stdout. *

+ * The message will be tagged with "Warning" on the output so the caller does not + * need to put such a prefix in the format string. + *

* Implementations should only display warnings in verbose mode. - * The message should be prefixed with "Warning:". * * @param warningFormat is an optional error format. If non-null, it will be printed * using a {@link Formatter} with the provided arguments. @@ -38,8 +40,10 @@ public interface ISdkLog { /** * Prints an error message on stderr. *

+ * The message will be tagged with "Error" on the output so the caller does not + * need to put such a prefix in the format string. + *

* Implementation should always display errors, independent of verbose mode. - * The message should be prefixed with "Error:". * * @param t is an optional {@link Throwable} or {@link Exception}. If non-null, it's * message will be printed out. diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java index 4342551ec..a6326630e 100644 --- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java +++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/avd/AvdManager.java @@ -279,7 +279,7 @@ public final class AvdManager { // AVD shouldn't already exist if removePrevious is false. if (log != null) { log.error(null, - "Folder %s is in the way. Use --force if you want to overwrite.", + "Folder %1$s is in the way. Use --force if you want to overwrite.", avdFolder.getAbsolutePath()); } return null; @@ -429,9 +429,9 @@ public final class AvdManager { if (log != null) { if (target.isPlatform()) { - log.printf("Created AVD '%s' based on %s\n", name, target.getName()); + log.printf("Created AVD '%1$s' based on %2$s\n", name, target.getName()); } else { - log.printf("Created AVD '%s' based on %s (%s)\n", name, target.getName(), + log.printf("Created AVD '%1$s' based on %2$s (%3$s)\n", name, target.getName(), target.getVendor()); } } @@ -563,29 +563,49 @@ public final class AvdManager { *

* This also remove it from the manager's list, The caller does not need to * call {@link #removeAvd(AvdInfo)} afterwards. + *

+ * This method is designed to somehow work with an unavailable AVD, that is an AVD that + * could not be loaded due to some error. That means this method still tries to remove + * the AVD ini file or its folder if it can be found. An error will be output if any of + * these operations fail. * * @param avdInfo the information on the AVD to delete */ public void deleteAvd(AvdInfo avdInfo, ISdkLog log) { try { + boolean error = false; + File f = avdInfo.getIniFile(); - if (f.exists()) { - log.warning("Deleting file %s", f.getCanonicalPath()); + if (f != null && f.exists()) { + log.warning("Deleting file %1$s", f.getCanonicalPath()); if (!f.delete()) { - log.error(null, "Failed to delete %s", f.getCanonicalPath()); + log.error(null, "Failed to delete %1$s", f.getCanonicalPath()); + error = true; } } - - f = new File(avdInfo.getPath()); - if (f.exists()) { - log.warning("Deleting folder %s", f.getCanonicalPath()); - recursiveDelete(f); - if (!f.delete()) { - log.error(null, "Failed to delete %s", f.getCanonicalPath()); + + String path = avdInfo.getPath(); + if (path != null) { + f = new File(path); + if (f.exists()) { + log.warning("Deleting folder %1$s", f.getCanonicalPath()); + recursiveDelete(f); + if (!f.delete()) { + log.error(null, "Failed to delete %1$s", f.getCanonicalPath()); + error = true; + } } } removeAvd(avdInfo); + + if (error) { + log.printf("AVD '%1$s' deleted with errors. See warnings above.", + avdInfo.getName()); + } else { + log.printf("AVD '%1$s' deleted.", avdInfo.getName()); + } + } catch (AndroidLocationException e) { log.error(e, null); } catch (IOException e) { @@ -611,14 +631,14 @@ public final class AvdManager { try { if (paramFolderPath != null) { File f = new File(avdInfo.getPath()); - log.warning("Moving '%s' to '%s'.", avdInfo.getPath(), paramFolderPath); + log.warning("Moving '%1$s' to '%2$s'.", avdInfo.getPath(), paramFolderPath); if (!f.renameTo(new File(paramFolderPath))) { - log.error(null, "Failed to move '%s' to '%s'.", + log.error(null, "Failed to move '%1$s' to '%2$s'.", avdInfo.getPath(), paramFolderPath); return false; } - // update avd info + // update AVD info AvdInfo info = new AvdInfo(avdInfo.getName(), paramFolderPath, avdInfo.getTarget(), avdInfo.getProperties()); mAvdList.remove(avdInfo); @@ -633,19 +653,22 @@ public final class AvdManager { File oldIniFile = avdInfo.getIniFile(); File newIniFile = AvdInfo.getIniFile(newName); - log.warning("Moving '%s' to '%s'.", oldIniFile.getPath(), newIniFile.getPath()); + log.warning("Moving '%1$s' to '%2$s'.", oldIniFile.getPath(), newIniFile.getPath()); if (!oldIniFile.renameTo(newIniFile)) { - log.error(null, "Failed to move '%s' to '%s'.", + log.error(null, "Failed to move '%1$s' to '%2$s'.", oldIniFile.getPath(), newIniFile.getPath()); return false; } - // update avd info + // update AVD info AvdInfo info = new AvdInfo(newName, avdInfo.getPath(), avdInfo.getTarget(), avdInfo.getProperties()); mAvdList.remove(avdInfo); mAvdList.add(info); } + + log.printf("AVD '%1$s' moved.", avdInfo.getName()); + } catch (AndroidLocationException e) { log.error(e, null); } catch (IOException e) { @@ -686,7 +709,8 @@ public final class AvdManager { // ensure folder validity. File folder = new File(avdRoot); if (folder.isFile()) { - throw new AndroidLocationException(String.format("%s is not a valid folder.", avdRoot)); + throw new AndroidLocationException( + String.format("%1$s is not a valid folder.", avdRoot)); } else if (folder.exists() == false) { // folder is not there, we create it and return folder.mkdirs(); @@ -727,7 +751,21 @@ public final class AvdManager { } } - public List getUnavailableAvdList() throws AndroidLocationException { + /** + * Computes the internal list of not available AVDs. + *

+ * These are the AVDs that failed to load for some reason or another. + * You can retrieve the load error using {@link AvdInfo#getError()}. + *

+ * These {@link AvdInfo} must not be used for usual operations (e.g. instanciating + * an emulator) or trying to use them for anything else but {@link #deleteAvd(AvdInfo, ISdkLog)} + * will have unpredictable results -- that is most likely the operation will fail. + * + * @return A list of unavailable AVDs, all with errors. The list can be null or empty if there + * are no AVDs to return. + * @throws AndroidLocationException if there's a problem getting android root directory. + */ + public List getUnavailableAvds() throws AndroidLocationException { AvdInfo[] avds = getAvds(); File[] allAvds = buildAvdFilesList(); if (allAvds == null || allAvds.length == 0) { @@ -776,7 +814,7 @@ public final class AvdManager { target = mSdk.getTargetFromHashString(targetHash); } - // load the avd properties. + // load the AVD properties. if (avdPath != null) { configIniFile = new File(avdPath, CONFIG_INI); } @@ -806,7 +844,7 @@ public final class AvdManager { } else if (targetHash == null) { error = String.format("Missing 'target' property in %1$s", name); } else if (target == null) { - error = String.format("Unknown 'target=%2$s' property in %1$s", name, targetHash); + error = String.format("Unknown target '%2$s' in %1$s", name, targetHash); } else if (properties == null) { error = String.format("Failed to parse properties from %1$s", avdPath); } @@ -834,7 +872,7 @@ public final class AvdManager { FileWriter writer = new FileWriter(iniFile); for (Entry entry : values.entrySet()) { - writer.write(String.format("%s=%s\n", entry.getKey(), entry.getValue())); + writer.write(String.format("%1$s=%2$s\n", entry.getKey(), entry.getValue())); } writer.close(); @@ -861,26 +899,25 @@ public final class AvdManager { ArrayList stdOutput = new ArrayList(); int status = grabProcessOutput(process, errorOutput, stdOutput, true /* waitForReaders */); - - if (status != 0) { - log.error(null, "Failed to create the SD card."); + + if (status == 0) { + return true; + } else { for (String error : errorOutput) { log.error(null, error); } - - return false; } - return true; } catch (InterruptedException e) { - log.error(null, "Failed to create the SD card."); + // pass, print error below } catch (IOException e) { - log.error(null, "Failed to create the SD card."); + // pass, print error below } + log.error(null, "Failed to create the SD card."); return false; } - + /** * Gets the stderr/stdout outputs of a process and returns when the process is done. * Both must be read or the process will block on windows. From 0f25507fb044b456ff45cc5d131cec6582ebe593 Mon Sep 17 00:00:00 2001 From: Raphael Moll <> Date: Tue, 31 Mar 2009 17:22:27 -0700 Subject: [PATCH 16/45] AI 143882: ADT #1743364: Refactor misc UI widgets together in package adt.ui. BUG=1743364 Automated import of CL 143882 --- .../com.android.ide.eclipse.adt/META-INF/MANIFEST.MF | 2 +- .../src/com/android/ide/eclipse/adt/AdtPlugin.java | 2 +- .../extractstring/ExtractStringInputPage.java | 2 +- .../wizards => adt/ui}/ConfigurationSelector.java | 2 +- .../ide/eclipse/{common => adt/ui}/EclipseUiHelper.java | 2 +- .../wizards => adt/ui}/ReferenceChooserDialog.java | 2 +- .../{editors/wizards => adt/ui}/ResourceChooser.java | 2 +- .../wizards => adt/ui}/ResourceContentProvider.java | 2 +- .../wizards => adt/ui}/ResourceLabelProvider.java | 2 +- .../adt/wizards/newxmlfile/NewXmlFileCreationPage.java | 4 ++-- .../ide/eclipse/editors/layout/GraphicalLayoutEditor.java | 8 ++++---- .../ide/eclipse/editors/layout/LayoutCreatorDialog.java | 4 ++-- .../android/ide/eclipse/editors/layout/LayoutEditor.java | 2 +- .../ide/eclipse/editors/layout/UiContentOutlinePage.java | 2 +- .../editors/resources/explorer/ResourceExplorerView.java | 4 ++-- .../eclipse/editors/uimodel/UiResourceAttributeNode.java | 4 ++-- 16 files changed, 23 insertions(+), 23 deletions(-) rename tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/{editors/wizards => adt/ui}/ConfigurationSelector.java (99%) rename tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/{common => adt/ui}/EclipseUiHelper.java (98%) rename tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/{editors/wizards => adt/ui}/ReferenceChooserDialog.java (99%) rename tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/{editors/wizards => adt/ui}/ResourceChooser.java (99%) rename tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/{editors/wizards => adt/ui}/ResourceContentProvider.java (98%) rename tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/{editors/wizards => adt/ui}/ResourceLabelProvider.java (99%) diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF b/tools/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF index 0ec97aa38..4b9d3a007 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF @@ -52,6 +52,7 @@ Export-Package: com.android.ide.eclipse.adt;x-friends:="com.android.ide.eclipse. com.android.ide.eclipse.adt.project.internal;x-friends:="com.android.ide.eclipse.tests", com.android.ide.eclipse.adt.sdk;x-friends:="com.android.ide.eclipse.tests", com.android.ide.eclipse.adt.wizards.newproject;x-friends:="com.android.ide.eclipse.tests", + com.android.ide.eclipse.adt.ui;x-friends:="com.android.ide.eclipse.tests", com.android.ide.eclipse.common;x-friends:="com.android.ide.eclipse.tests", com.android.ide.eclipse.common.project;x-friends:="com.android.ide.eclipse.tests", com.android.ide.eclipse.common.resources;x-friends:="com.android.ide.eclipse.tests", @@ -77,7 +78,6 @@ Export-Package: com.android.ide.eclipse.adt;x-friends:="com.android.ide.eclipse. com.android.ide.eclipse.editors.ui;x-friends:="com.android.ide.eclipse.tests", com.android.ide.eclipse.editors.ui.tree;x-friends:="com.android.ide.eclipse.tests", com.android.ide.eclipse.editors.uimodel;x-friends:="com.android.ide.eclipse.tests", - com.android.ide.eclipse.editors.wizards;x-friends:="com.android.ide.eclipse.tests", com.android.ide.eclipse.editors.xml;x-friends:="com.android.ide.eclipse.tests", com.android.ide.eclipse.editors.xml.descriptors;x-friends:="com.android.ide.eclipse.tests" diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java index 42db64a61..4a7a002e2 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/AdtPlugin.java @@ -29,8 +29,8 @@ import com.android.ide.eclipse.adt.sdk.AndroidTargetParser; import com.android.ide.eclipse.adt.sdk.LoadStatus; import com.android.ide.eclipse.adt.sdk.Sdk; import com.android.ide.eclipse.adt.sdk.Sdk.ITargetChangeListener; +import com.android.ide.eclipse.adt.ui.EclipseUiHelper; import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.common.EclipseUiHelper; import com.android.ide.eclipse.common.SdkStatsHelper; import com.android.ide.eclipse.common.StreamHelper; import com.android.ide.eclipse.common.project.BaseProjectHelper; diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/refactorings/extractstring/ExtractStringInputPage.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/refactorings/extractstring/ExtractStringInputPage.java index 5ffeeb05f..9822b32e7 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/refactorings/extractstring/ExtractStringInputPage.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/refactorings/extractstring/ExtractStringInputPage.java @@ -17,10 +17,10 @@ package com.android.ide.eclipse.adt.refactorings.extractstring; +import com.android.ide.eclipse.adt.ui.ConfigurationSelector; import com.android.ide.eclipse.common.AndroidConstants; import com.android.ide.eclipse.editors.resources.configurations.FolderConfiguration; import com.android.ide.eclipse.editors.resources.manager.ResourceFolderType; -import com.android.ide.eclipse.editors.wizards.ConfigurationSelector; import com.android.sdklib.SdkConstants; import org.eclipse.core.resources.IFolder; diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ConfigurationSelector.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/ui/ConfigurationSelector.java similarity index 99% rename from tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ConfigurationSelector.java rename to tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/ui/ConfigurationSelector.java index 4a05b1ee5..651d1e016 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ConfigurationSelector.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/ui/ConfigurationSelector.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.ide.eclipse.editors.wizards; +package com.android.ide.eclipse.adt.ui; import com.android.ide.eclipse.editors.resources.configurations.CountryCodeQualifier; import com.android.ide.eclipse.editors.resources.configurations.FolderConfiguration; diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/EclipseUiHelper.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/ui/EclipseUiHelper.java similarity index 98% rename from tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/EclipseUiHelper.java rename to tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/ui/EclipseUiHelper.java index 6dc856233..55878bf28 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/common/EclipseUiHelper.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/ui/EclipseUiHelper.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.ide.eclipse.common; +package com.android.ide.eclipse.adt.ui; import org.eclipse.ui.IViewPart; import org.eclipse.ui.IWorkbenchPage; diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ReferenceChooserDialog.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/ui/ReferenceChooserDialog.java similarity index 99% rename from tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ReferenceChooserDialog.java rename to tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/ui/ReferenceChooserDialog.java index 6913ce07d..e141396c5 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ReferenceChooserDialog.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/ui/ReferenceChooserDialog.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.ide.eclipse.editors.wizards; +package com.android.ide.eclipse.adt.ui; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.common.resources.IResourceRepository; diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ResourceChooser.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/ui/ResourceChooser.java similarity index 99% rename from tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ResourceChooser.java rename to tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/ui/ResourceChooser.java index 60a627b52..4290f6b79 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ResourceChooser.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/ui/ResourceChooser.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.ide.eclipse.editors.wizards; +package com.android.ide.eclipse.adt.ui; import com.android.ide.eclipse.common.resources.IResourceRepository; import com.android.ide.eclipse.common.resources.ResourceItem; diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ResourceContentProvider.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/ui/ResourceContentProvider.java similarity index 98% rename from tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ResourceContentProvider.java rename to tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/ui/ResourceContentProvider.java index 7c6a539ca..3792fe312 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ResourceContentProvider.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/ui/ResourceContentProvider.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.ide.eclipse.editors.wizards; +package com.android.ide.eclipse.adt.ui; import com.android.ide.eclipse.common.resources.IResourceRepository; import com.android.ide.eclipse.common.resources.ResourceItem; diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ResourceLabelProvider.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/ui/ResourceLabelProvider.java similarity index 99% rename from tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ResourceLabelProvider.java rename to tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/ui/ResourceLabelProvider.java index 024d08433..f7c26346a 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/wizards/ResourceLabelProvider.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/ui/ResourceLabelProvider.java @@ -14,7 +14,7 @@ * limitations under the License. */ -package com.android.ide.eclipse.editors.wizards; +package com.android.ide.eclipse.adt.ui; import com.android.ide.eclipse.common.resources.IIdResourceItem; import com.android.ide.eclipse.common.resources.ResourceItem; diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newxmlfile/NewXmlFileCreationPage.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newxmlfile/NewXmlFileCreationPage.java index f3cbfa221..f85050444 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newxmlfile/NewXmlFileCreationPage.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newxmlfile/NewXmlFileCreationPage.java @@ -21,6 +21,8 @@ import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.sdk.AndroidTargetData; import com.android.ide.eclipse.adt.sdk.Sdk; import com.android.ide.eclipse.adt.sdk.Sdk.ITargetChangeListener; +import com.android.ide.eclipse.adt.ui.ConfigurationSelector; +import com.android.ide.eclipse.adt.ui.ConfigurationSelector.ConfigurationState; import com.android.ide.eclipse.common.AndroidConstants; import com.android.ide.eclipse.common.project.ProjectChooserHelper; import com.android.ide.eclipse.editors.descriptors.DocumentDescriptor; @@ -31,8 +33,6 @@ import com.android.ide.eclipse.editors.resources.configurations.FolderConfigurat import com.android.ide.eclipse.editors.resources.configurations.ResourceQualifier; import com.android.ide.eclipse.editors.resources.descriptors.ResourcesDescriptors; import com.android.ide.eclipse.editors.resources.manager.ResourceFolderType; -import com.android.ide.eclipse.editors.wizards.ConfigurationSelector; -import com.android.ide.eclipse.editors.wizards.ConfigurationSelector.ConfigurationState; import com.android.sdklib.IAndroidTarget; import com.android.sdklib.SdkConstants; diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/GraphicalLayoutEditor.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/GraphicalLayoutEditor.java index 12d49fe27..e22382034 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/GraphicalLayoutEditor.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/GraphicalLayoutEditor.java @@ -22,6 +22,10 @@ import com.android.ide.eclipse.adt.sdk.LoadStatus; import com.android.ide.eclipse.adt.sdk.Sdk; import com.android.ide.eclipse.adt.sdk.AndroidTargetData.LayoutBridge; import com.android.ide.eclipse.adt.sdk.Sdk.ITargetChangeListener; +import com.android.ide.eclipse.adt.ui.ConfigurationSelector.DensityVerifier; +import com.android.ide.eclipse.adt.ui.ConfigurationSelector.DimensionVerifier; +import com.android.ide.eclipse.adt.ui.ConfigurationSelector.LanguageRegionVerifier; +import com.android.ide.eclipse.adt.ui.ConfigurationSelector.MobileCodeVerifier; import com.android.ide.eclipse.common.resources.ResourceType; import com.android.ide.eclipse.editors.IconFactory; import com.android.ide.eclipse.editors.layout.LayoutEditor.UiEditorActions; @@ -55,10 +59,6 @@ import com.android.ide.eclipse.editors.ui.tree.CopyCutAction; import com.android.ide.eclipse.editors.ui.tree.PasteAction; import com.android.ide.eclipse.editors.uimodel.UiDocumentNode; import com.android.ide.eclipse.editors.uimodel.UiElementNode; -import com.android.ide.eclipse.editors.wizards.ConfigurationSelector.DensityVerifier; -import com.android.ide.eclipse.editors.wizards.ConfigurationSelector.DimensionVerifier; -import com.android.ide.eclipse.editors.wizards.ConfigurationSelector.LanguageRegionVerifier; -import com.android.ide.eclipse.editors.wizards.ConfigurationSelector.MobileCodeVerifier; import com.android.layoutlib.api.ILayoutLog; import com.android.layoutlib.api.ILayoutResult; import com.android.layoutlib.api.IProjectCallback; diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutCreatorDialog.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutCreatorDialog.java index c4a8f5cc1..69402381a 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutCreatorDialog.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutCreatorDialog.java @@ -16,12 +16,12 @@ package com.android.ide.eclipse.editors.layout; +import com.android.ide.eclipse.adt.ui.ConfigurationSelector; +import com.android.ide.eclipse.adt.ui.ConfigurationSelector.ConfigurationState; import com.android.ide.eclipse.editors.IconFactory; import com.android.ide.eclipse.editors.resources.configurations.FolderConfiguration; import com.android.ide.eclipse.editors.resources.configurations.ResourceQualifier; import com.android.ide.eclipse.editors.resources.manager.ResourceFolderType; -import com.android.ide.eclipse.editors.wizards.ConfigurationSelector; -import com.android.ide.eclipse.editors.wizards.ConfigurationSelector.ConfigurationState; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.TrayDialog; diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutEditor.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutEditor.java index f3a5113a9..7bed7ce6a 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutEditor.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/LayoutEditor.java @@ -18,8 +18,8 @@ package com.android.ide.eclipse.editors.layout; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.sdk.AndroidTargetData; +import com.android.ide.eclipse.adt.ui.EclipseUiHelper; import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.common.EclipseUiHelper; import com.android.ide.eclipse.editors.AndroidEditor; import com.android.ide.eclipse.editors.descriptors.DocumentDescriptor; import com.android.ide.eclipse.editors.resources.manager.ResourceFolder; diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/UiContentOutlinePage.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/UiContentOutlinePage.java index 536e9020b..4e0e35f06 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/UiContentOutlinePage.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/layout/UiContentOutlinePage.java @@ -17,7 +17,7 @@ package com.android.ide.eclipse.editors.layout; -import com.android.ide.eclipse.common.EclipseUiHelper; +import com.android.ide.eclipse.adt.ui.EclipseUiHelper; import com.android.ide.eclipse.editors.IconFactory; import com.android.ide.eclipse.editors.layout.parts.UiDocumentTreeEditPart; import com.android.ide.eclipse.editors.layout.parts.UiElementTreeEditPart; diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/explorer/ResourceExplorerView.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/explorer/ResourceExplorerView.java index d1d88917f..b61eddc4d 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/explorer/ResourceExplorerView.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/resources/explorer/ResourceExplorerView.java @@ -17,14 +17,14 @@ package com.android.ide.eclipse.editors.resources.explorer; import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.ide.eclipse.adt.ui.ResourceContentProvider; +import com.android.ide.eclipse.adt.ui.ResourceLabelProvider; import com.android.ide.eclipse.common.AndroidConstants; import com.android.ide.eclipse.editors.resources.manager.ProjectResourceItem; import com.android.ide.eclipse.editors.resources.manager.ProjectResources; import com.android.ide.eclipse.editors.resources.manager.ResourceFile; import com.android.ide.eclipse.editors.resources.manager.ResourceManager; import com.android.ide.eclipse.editors.resources.manager.ResourceMonitor.IResourceEventListener; -import com.android.ide.eclipse.editors.wizards.ResourceContentProvider; -import com.android.ide.eclipse.editors.wizards.ResourceLabelProvider; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiResourceAttributeNode.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiResourceAttributeNode.java index 32cac9f2b..654e792cc 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiResourceAttributeNode.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/editors/uimodel/UiResourceAttributeNode.java @@ -17,6 +17,8 @@ package com.android.ide.eclipse.editors.uimodel; import com.android.ide.eclipse.adt.sdk.AndroidTargetData; +import com.android.ide.eclipse.adt.ui.ReferenceChooserDialog; +import com.android.ide.eclipse.adt.ui.ResourceChooser; import com.android.ide.eclipse.common.resources.IResourceRepository; import com.android.ide.eclipse.common.resources.ResourceItem; import com.android.ide.eclipse.common.resources.ResourceType; @@ -26,8 +28,6 @@ import com.android.ide.eclipse.editors.descriptors.DescriptorsUtils; import com.android.ide.eclipse.editors.descriptors.TextAttributeDescriptor; import com.android.ide.eclipse.editors.resources.manager.ResourceManager; import com.android.ide.eclipse.editors.ui.SectionHelper; -import com.android.ide.eclipse.editors.wizards.ReferenceChooserDialog; -import com.android.ide.eclipse.editors.wizards.ResourceChooser; import org.eclipse.core.resources.IProject; import org.eclipse.jface.window.Window; From 09f36bfffbc3af1f90b1c9c58b82fa30409d2496 Mon Sep 17 00:00:00 2001 From: Brett Chabot <> Date: Tue, 31 Mar 2009 19:13:57 -0700 Subject: [PATCH 17/45] AI 143917: ADT Android JUnit: Change logic to provide an explicit project or package to run to the device InstrumentationTestRunner, instead of providing the potentially huge list of test classes. Discontinue support for running all tests in a source folder. BUG=1749513 Automated import of CL 143917 --- .../testrunner/RemoteAndroidTestRunner.java | 11 ++ .../RemoteAndroidTestRunnerTest.java | 16 ++- .../META-INF/MANIFEST.MF | 3 +- .../com.android.ide.eclipse.adt/plugin.xml | 12 +- .../junit/AndroidJUnitLaunchAction.java | 68 ++++----- .../AndroidJUnitLaunchConfigDelegate.java | 83 ++++++++++- .../AndroidJUnitLaunchConfigurationTab.java | 34 ++++- .../junit/AndroidJUnitPropertyTester.java | 130 ++++++++++++++++++ .../junit/runtime/AndroidJUnitLaunchInfo.java | 103 ++++++++++++-- .../junit/runtime/RemoteAdtTestRunner.java | 24 ++-- 10 files changed, 404 insertions(+), 80 deletions(-) create mode 100644 tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitPropertyTester.java diff --git a/tools/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunner.java b/tools/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunner.java index 999542634..9dd1d1640 100644 --- a/tools/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunner.java +++ b/tools/ddms/libs/ddmlib/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunner.java @@ -49,6 +49,7 @@ public class RemoteAndroidTestRunner { private static final String LOG_ARG_NAME = "log"; private static final String DEBUG_ARG_NAME = "debug"; private static final String COVERAGE_ARG_NAME = "coverage"; + private static final String PACKAGE_ARG_NAME = "package"; /** * Creates a remote Android test runner. @@ -145,6 +146,16 @@ public class RemoteAndroidTestRunner { setClassName(className + METHOD_SEPARATOR + testName); } + /** + * Sets to run all tests in specified package + * Must be called before 'run'. + * + * @param packageName fully qualified package name (eg x.y.z) + */ + public void setTestPackageName(String packageName) { + addInstrumentationArg(PACKAGE_ARG_NAME, packageName); + } + /** * Adds a argument to include in instrumentation command. *

diff --git a/tools/ddms/libs/ddmlib/tests/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunnerTest.java b/tools/ddms/libs/ddmlib/tests/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunnerTest.java index 6a653ad05..864e219fc 100644 --- a/tools/ddms/libs/ddmlib/tests/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunnerTest.java +++ b/tools/ddms/libs/ddmlib/tests/src/com/android/ddmlib/testrunner/RemoteAndroidTestRunnerTest.java @@ -17,16 +17,17 @@ package com.android.ddmlib.testrunner; import com.android.ddmlib.Client; -import com.android.ddmlib.Device.DeviceState; import com.android.ddmlib.FileListingService; import com.android.ddmlib.IDevice; import com.android.ddmlib.IShellOutputReceiver; -import com.android.ddmlib.log.LogReceiver; import com.android.ddmlib.RawImage; import com.android.ddmlib.SyncService; +import com.android.ddmlib.Device.DeviceState; +import com.android.ddmlib.log.LogReceiver; import java.io.IOException; import java.util.Map; + import junit.framework.TestCase; /** @@ -80,6 +81,17 @@ public class RemoteAndroidTestRunnerTest extends TestCase { testName, TEST_PACKAGE, TEST_RUNNER), mMockDevice.getLastShellCommand()); } + /** + * Test the building of the instrumentation runner command with test package set. + */ + public void testRunWithPackage() { + final String packageName = "foo.test"; + mRunner.setTestPackageName(packageName); + mRunner.run(new EmptyListener()); + assertStringsEquals(String.format("am instrument -w -r -e package %s %s/%s", packageName, + TEST_PACKAGE, TEST_RUNNER), mMockDevice.getLastShellCommand()); + } + /** * Test the building of the instrumentation runner command with extra argument added. */ diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF b/tools/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF index 4b9d3a007..8092f3a5e 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/META-INF/MANIFEST.MF @@ -43,7 +43,8 @@ Require-Bundle: com.android.ide.eclipse.ddms, org.eclipse.jdt.junit, org.eclipse.jdt.junit.runtime, org.eclipse.ltk.core.refactoring, - org.eclipse.ltk.ui.refactoring + org.eclipse.ltk.ui.refactoring, + org.eclipse.core.expressions Eclipse-LazyStart: true Export-Package: com.android.ide.eclipse.adt;x-friends:="com.android.ide.eclipse.tests", com.android.ide.eclipse.adt.build;x-friends:="com.android.ide.eclipse.tests", diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml b/tools/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml index a75b8b915..35ceba76e 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/plugin.xml @@ -563,7 +563,7 @@ - + @@ -595,4 +595,14 @@ id="com.android.ide.eclipse.adt.refactoring.extract.string"> + + + + diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchAction.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchAction.java index 747fcfe5c..9bcc63d06 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchAction.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchAction.java @@ -24,7 +24,6 @@ import com.android.ide.eclipse.adt.launch.junit.runtime.RemoteAdtTestRunner; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; -import org.eclipse.debug.core.DebugException; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchManager; @@ -39,18 +38,15 @@ import org.eclipse.jdt.launching.VMRunnerConfiguration; */ class AndroidJUnitLaunchAction implements IAndroidLaunchAction { - private String mTestPackage; - private String mRunner; + private final AndroidJUnitLaunchInfo mLaunchInfo; /** * Creates a AndroidJUnitLaunchAction. * - * @param testPackage the Android application package that contains the tests to run - * @param runner the InstrumentationTestRunner that will execute the tests + * @param launchInfo the {@link AndroidJUnitLaunchInfo} for the JUnit run */ - public AndroidJUnitLaunchAction(String testPackage, String runner) { - mTestPackage = testPackage; - mRunner = runner; + public AndroidJUnitLaunchAction(AndroidJUnitLaunchInfo launchInfo) { + mLaunchInfo = launchInfo; } /** @@ -60,17 +56,21 @@ class AndroidJUnitLaunchAction implements IAndroidLaunchAction { * @see IAndroidLaunchAction#doLaunchAction(DelayedLaunchInfo, IDevice) */ public boolean doLaunchAction(DelayedLaunchInfo info, IDevice device) { - String msg = String.format("Launching instrumentation %s on device %s", mRunner, - device.getSerialNumber()); + String msg = String.format("Launching instrumentation %s on device %s", + mLaunchInfo.getRunner(), device.getSerialNumber()); AdtPlugin.printToConsole(info.getProject(), msg); try { - JUnitLaunchDelegate junitDelegate = new JUnitLaunchDelegate(info, device); + mLaunchInfo.setDebugMode(info.isDebugMode()); + mLaunchInfo.setDevice(info.getDevice()); + mLaunchInfo.setLaunch(info.getLaunch()); + JUnitLaunchDelegate junitDelegate = new JUnitLaunchDelegate(mLaunchInfo); final String mode = info.isDebugMode() ? ILaunchManager.DEBUG_MODE : ILaunchManager.RUN_MODE; + junitDelegate.launch(info.getLaunch().getLaunchConfiguration(), mode, info.getLaunch(), info.getMonitor()); - + // TODO: need to add AMReceiver-type functionality somewhere } catch (CoreException e) { AdtPlugin.printErrorToConsole(info.getProject(), "Failed to launch test"); @@ -82,20 +82,18 @@ class AndroidJUnitLaunchAction implements IAndroidLaunchAction { * {@inheritDoc} */ public String getLaunchDescription() { - return String.format("%s JUnit launch", mRunner); + return String.format("%s JUnit launch", mLaunchInfo.getRunner()); } /** * Extends the JDT JUnit launch delegate to allow for JUnit UI reuse. */ - private class JUnitLaunchDelegate extends JUnitLaunchConfigurationDelegate { + private static class JUnitLaunchDelegate extends JUnitLaunchConfigurationDelegate { - private IDevice mDevice; - private DelayedLaunchInfo mLaunchInfo; + private AndroidJUnitLaunchInfo mLaunchInfo; - public JUnitLaunchDelegate(DelayedLaunchInfo info, IDevice device) { - mLaunchInfo = info; - mDevice = device; + public JUnitLaunchDelegate(AndroidJUnitLaunchInfo launchInfo) { + mLaunchInfo = launchInfo; } /* (non-Javadoc) @@ -110,34 +108,28 @@ class AndroidJUnitLaunchAction implements IAndroidLaunchAction { /** * {@inheritDoc} - * @throws CoreException * @see org.eclipse.jdt.junit.launcher.JUnitLaunchConfigurationDelegate#verifyMainTypeName(org.eclipse.debug.core.ILaunchConfiguration) */ @Override - public String verifyMainTypeName(ILaunchConfiguration configuration) throws CoreException { + public String verifyMainTypeName(ILaunchConfiguration configuration) { return "com.android.ide.eclipse.adt.junit.internal.runner.RemoteAndroidTestRunner"; //$NON-NLS-1$ } /** * Overrides parent to return a VM Runner implementation which launches a thread, rather * than a separate VM process - * @throws CoreException */ @Override - public IVMRunner getVMRunner(ILaunchConfiguration configuration, String mode) - throws CoreException { - return new VMTestRunner(new AndroidJUnitLaunchInfo(mLaunchInfo.getProject(), - mTestPackage, mRunner, mLaunchInfo.isDebugMode(), mDevice)); + public IVMRunner getVMRunner(ILaunchConfiguration configuration, String mode) { + return new VMTestRunner(mLaunchInfo); } /** * {@inheritDoc} - * @throws CoreException * @see org.eclipse.debug.core.model.LaunchConfigurationDelegate#getLaunch(org.eclipse.debug.core.ILaunchConfiguration, java.lang.String) */ @Override - public ILaunch getLaunch(ILaunchConfiguration configuration, String mode) - throws CoreException { + public ILaunch getLaunch(ILaunchConfiguration configuration, String mode) { return mLaunchInfo.getLaunch(); } } @@ -161,7 +153,7 @@ class AndroidJUnitLaunchAction implements IAndroidLaunchAction { IProgressMonitor monitor) throws CoreException { TestRunnerProcess runnerProcess = - new TestRunnerProcess(config, launch, mJUnitInfo); + new TestRunnerProcess(config, mJUnitInfo); runnerProcess.start(); launch.addProcess(runnerProcess); } @@ -173,15 +165,12 @@ class AndroidJUnitLaunchAction implements IAndroidLaunchAction { private static class TestRunnerProcess extends Thread implements IProcess { private final VMRunnerConfiguration mRunConfig; - private final ILaunch mLaunch; private final AndroidJUnitLaunchInfo mJUnitInfo; private RemoteAdtTestRunner mTestRunner = null; private boolean mIsTerminated = false; - TestRunnerProcess(VMRunnerConfiguration runConfig, ILaunch launch, - AndroidJUnitLaunchInfo info) { + TestRunnerProcess(VMRunnerConfiguration runConfig, AndroidJUnitLaunchInfo info) { mRunConfig = runConfig; - mLaunch = launch; mJUnitInfo = info; } @@ -194,10 +183,9 @@ class AndroidJUnitLaunchAction implements IAndroidLaunchAction { /** * {@inheritDoc} - * @throws DebugException * @see org.eclipse.debug.core.model.IProcess#getExitValue() */ - public int getExitValue() throws DebugException { + public int getExitValue() { return 0; } @@ -205,14 +193,14 @@ class AndroidJUnitLaunchAction implements IAndroidLaunchAction { * @see org.eclipse.debug.core.model.IProcess#getLabel() */ public String getLabel() { - return mLaunch.getLaunchMode(); + return mJUnitInfo.getLaunch().getLaunchMode(); } /* (non-Javadoc) * @see org.eclipse.debug.core.model.IProcess#getLaunch() */ public ILaunch getLaunch() { - return mLaunch; + return mJUnitInfo.getLaunch(); } /* (non-Javadoc) @@ -254,10 +242,9 @@ class AndroidJUnitLaunchAction implements IAndroidLaunchAction { /** * {@inheritDoc} - * @throws DebugException * @see org.eclipse.debug.core.model.ITerminate#terminate() */ - public void terminate() throws DebugException { + public void terminate() { if (mTestRunner != null) { mTestRunner.terminate(); } @@ -274,3 +261,4 @@ class AndroidJUnitLaunchAction implements IAndroidLaunchAction { } } } + diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchConfigDelegate.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchConfigDelegate.java index fa8e4b01a..543daf06f 100755 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchConfigDelegate.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchConfigDelegate.java @@ -22,6 +22,7 @@ import com.android.ide.eclipse.adt.launch.AndroidLaunchConfiguration; import com.android.ide.eclipse.adt.launch.AndroidLaunchController; import com.android.ide.eclipse.adt.launch.IAndroidLaunchAction; import com.android.ide.eclipse.adt.launch.LaunchConfigDelegate; +import com.android.ide.eclipse.adt.launch.junit.runtime.AndroidJUnitLaunchInfo; import com.android.ide.eclipse.common.AndroidConstants; import com.android.ide.eclipse.common.project.AndroidManifestParser; import com.android.ide.eclipse.common.project.BaseProjectHelper; @@ -32,8 +33,11 @@ import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.internal.junit.launcher.JUnitLaunchConfigurationConstants; import org.eclipse.jdt.internal.junit.launcher.TestKindRegistry; +import org.eclipse.jdt.launching.IJavaLaunchConfigurationConstants; /** * Run configuration that can execute JUnit tests on an Android platform. @@ -47,6 +51,7 @@ public class AndroidJUnitLaunchConfigDelegate extends LaunchConfigDelegate { /** Launch config attribute that stores instrumentation runner. */ static final String ATTR_INSTR_NAME = AdtPlugin.PLUGIN_ID + ".instrumentation"; //$NON-NLS-1$ + private static final String EMPTY_STRING = ""; //$NON-NLS-1$ @Override @@ -55,7 +60,7 @@ public class AndroidJUnitLaunchConfigDelegate extends LaunchConfigDelegate { AndroidLaunchConfiguration config, AndroidLaunchController controller, IFile applicationPackage, AndroidManifestParser manifestParser) { - String testPackage = manifestParser.getPackage(); + String appPackage = manifestParser.getPackage(); String runner = getRunner(project, configuration, manifestParser); if (runner == null) { AdtPlugin.displayError("Android Launch", @@ -63,14 +68,62 @@ public class AndroidJUnitLaunchConfigDelegate extends LaunchConfigDelegate { androidLaunch.stopLaunch(); return; } + AndroidJUnitLaunchInfo junitLaunchInfo = new AndroidJUnitLaunchInfo(project, appPackage, + runner); + junitLaunchInfo.setTestClass(getTestClass(configuration)); + junitLaunchInfo.setTestPackage(getTestPackage(configuration)); + junitLaunchInfo.setTestMethod(getTestMethod(configuration)); - IAndroidLaunchAction junitLaunch = new AndroidJUnitLaunchAction(testPackage, runner); + IAndroidLaunchAction junitLaunch = new AndroidJUnitLaunchAction(junitLaunchInfo); controller.launch(project, mode, applicationPackage, manifestParser.getPackage(), manifestParser.getDebuggable(), manifestParser.getApiLevelRequirement(), junitLaunch, config, androidLaunch, monitor); } + /** + * Returns the test package stored in the launch configuration, or null if not + * specified. + * + * @param configuration the {@link ILaunchConfiguration} to retrieve the test package info from + * @return the test package or null. + */ + private String getTestPackage(ILaunchConfiguration configuration) { + // try to retrieve a package name from the JUnit container attribute + String containerHandle = getStringLaunchAttribute( + JUnitLaunchConfigurationConstants.ATTR_TEST_CONTAINER, configuration); + if (containerHandle != null && containerHandle.length() > 0) { + IJavaElement element = JavaCore.create(containerHandle); + // containerHandle could be a IProject, check if its a java package + if (element.getElementType() == IJavaElement.PACKAGE_FRAGMENT) { + return element.getElementName(); + } + } + return null; + } + + /** + * Returns the test class stored in the launch configuration. + * + * @param configuration the {@link ILaunchConfiguration} to retrieve the test class info from + * @return the test class. null if not specified. + */ + private String getTestClass(ILaunchConfiguration configuration) { + return getStringLaunchAttribute(IJavaLaunchConfigurationConstants.ATTR_MAIN_TYPE_NAME, + configuration); + } + + /** + * Returns the test method stored in the launch configuration. + * + * @param configuration the {@link ILaunchConfiguration} to retrieve the test method info from + * @return the test method. null if not specified. + */ + private String getTestMethod(ILaunchConfiguration configuration) { + return getStringLaunchAttribute(JUnitLaunchConfigurationConstants.ATTR_TEST_METHOD_NAME, + configuration); + } + /** * Gets a instrumentation runner for the launch. *

@@ -114,11 +167,29 @@ public class AndroidJUnitLaunchConfigDelegate extends LaunchConfigDelegate { } private String getRunnerFromConfig(ILaunchConfiguration configuration) throws CoreException { - String runner = configuration.getAttribute(ATTR_INSTR_NAME, EMPTY_STRING); - if (runner.length() < 1) { - return null; + return getStringLaunchAttribute(ATTR_INSTR_NAME, configuration); + } + + /** + * Helper method to retrieve a string attribute from the launch configuration + * + * @param attributeName name of the launch attribute + * @param configuration the {@link ILaunchConfiguration} to retrieve the attribute from + * @return the attribute's value. null if not found. + */ + private String getStringLaunchAttribute(String attributeName, + ILaunchConfiguration configuration) { + try { + String attrValue = configuration.getAttribute(attributeName, EMPTY_STRING); + if (attrValue.length() < 1) { + return null; + } + return attrValue; + } catch (CoreException e) { + AdtPlugin.log(e, String.format("Error when retrieving launch info %1$s", //$NON-NLS-1$ + attributeName)); } - return runner; + return null; } /** diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchConfigurationTab.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchConfigurationTab.java index eb5748269..584d45eb1 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchConfigurationTab.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitLaunchConfigurationTab.java @@ -18,6 +18,7 @@ package com.android.ide.eclipse.adt.launch.junit; import com.android.ide.eclipse.adt.AdtPlugin; import com.android.ide.eclipse.adt.launch.MainLaunchConfigTab; import com.android.ide.eclipse.common.AndroidConstants; +import com.android.ide.eclipse.common.project.BaseProjectHelper; import com.android.ide.eclipse.common.project.ProjectChooserHelper; import org.eclipse.core.resources.IProject; @@ -241,7 +242,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat private void createTestContainerSelectionGroup(Composite comp) { mTestContainerRadioButton = new Button(comp, SWT.RADIO); mTestContainerRadioButton.setText( - JUnitMessages.JUnitLaunchConfigurationTab_label_containerTest); + "Run all tests in the selected project, or package"); GridData gd = new GridData(); gd.horizontalSpan = 3; mTestContainerRadioButton.setLayoutData(gd); @@ -249,12 +250,12 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat public void widgetSelected(SelectionEvent e) { if (mTestContainerRadioButton.getSelection()) { testModeChanged(); - } + } } public void widgetDefaultSelected(SelectionEvent e) { } }); - + mContainerText = new Text(comp, SWT.SINGLE | SWT.BORDER | SWT.READ_ONLY); gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalIndent = 25; @@ -265,7 +266,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat updateLaunchConfigurationDialog(); } }); - + mContainerSearchButton = new Button(comp, SWT.PUSH); mContainerSearchButton.setText(JUnitMessages.JUnitLaunchConfigurationTab_label_search); mContainerSearchButton.addSelectionListener(new SelectionAdapter() { @@ -821,7 +822,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat @SuppressWarnings("unchecked") private IJavaElement chooseContainer(IJavaElement initElement) { - Class[] acceptedClasses = new Class[] { IPackageFragmentRoot.class, IJavaProject.class, + Class[] acceptedClasses = new Class[] { IJavaProject.class, IPackageFragment.class }; TypedElementSelectionValidator validator = new TypedElementSelectionValidator( acceptedClasses, false) { @@ -839,7 +840,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat if (element instanceof IPackageFragmentRoot && ((IPackageFragmentRoot) element).isArchive()) { return false; - } + } try { if (element instanceof IPackageFragment && !((IPackageFragment) element).hasChildren()) { @@ -852,7 +853,7 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat } }; - StandardJavaElementContentProvider provider = new StandardJavaElementContentProvider(); + AndroidJavaElementContentProvider provider = new AndroidJavaElementContentProvider(); ILabelProvider labelProvider = new JavaElementLabelProvider( JavaElementLabelProvider.SHOW_DEFAULT); ElementTreeSelectionDialog dialog = new ElementTreeSelectionDialog(getShell(), @@ -974,4 +975,23 @@ public class AndroidJUnitLaunchConfigurationTab extends AbstractLaunchConfigurat mInstrumentations = null; mInstrumentationCombo.removeAll(); } + + /** + * Overrides the {@link StandardJavaElementContentProvider} to only display Android projects + */ + private static class AndroidJavaElementContentProvider + extends StandardJavaElementContentProvider { + + /** + * Override parent to return only Android projects if at the root. Otherwise, use parent + * functionality. + */ + @Override + public Object[] getChildren(Object element) { + if (element instanceof IJavaModel) { + return BaseProjectHelper.getAndroidProjects((IJavaModel) element); + } + return super.getChildren(element); + } + } } diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitPropertyTester.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitPropertyTester.java new file mode 100644 index 000000000..eadafee77 --- /dev/null +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/AndroidJUnitPropertyTester.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php + * + * 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. + */ +package com.android.ide.eclipse.adt.launch.junit; + +import org.eclipse.core.expressions.PropertyTester; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.core.runtime.IAdaptable; +import org.eclipse.jdt.core.IClassFile; +import org.eclipse.jdt.core.ICompilationUnit; +import org.eclipse.jdt.core.IJavaElement; +import org.eclipse.jdt.core.IMember; +import org.eclipse.jdt.core.IPackageFragment; +import org.eclipse.jdt.core.IType; +import org.eclipse.jdt.core.JavaCore; +import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.internal.junit.util.TestSearchEngine; + +/** + * A {@link PropertyTester} that checks if selected elements can be run as Android + * JUnit tests. + *

+ * Based on org.eclipse.jdt.internal.junit.JUnitPropertyTester. The only substantial difference in + * this implementation is source folders cannot be run as Android JUnit. + */ +@SuppressWarnings("restriction") +public class AndroidJUnitPropertyTester extends PropertyTester { + private static final String PROPERTY_IS_TEST = "isTest"; //$NON-NLS-1$ + + private static final String PROPERTY_CAN_LAUNCH_AS_JUNIT_TEST = "canLaunchAsJUnit"; //$NON-NLS-1$ + + /* (non-Javadoc) + * @see org.eclipse.jdt.internal.corext.refactoring.participants.properties.IPropertyEvaluator#test(java.lang.Object, java.lang.String, java.lang.String) + */ + public boolean test(Object receiver, String property, Object[] args, Object expectedValue) { + if (!(receiver instanceof IAdaptable)) { + final String elementName = (receiver == null ? "null" : //$NON-NLS-1$ + receiver.getClass().getName()); + throw new IllegalArgumentException( + String.format("Element must be of type IAdaptable, is %s", //$NON-NLS-1$ + elementName)); + } + + IJavaElement element; + if (receiver instanceof IJavaElement) { + element = (IJavaElement) receiver; + } else if (receiver instanceof IResource) { + element = JavaCore.create((IResource) receiver); + if (element == null) { + return false; + } + } else { // is IAdaptable + element= (IJavaElement) ((IAdaptable) receiver).getAdapter(IJavaElement.class); + if (element == null) { + IResource resource = (IResource) ((IAdaptable) receiver).getAdapter( + IResource.class); + element = JavaCore.create(resource); + if (element == null) { + return false; + } + } + } + if (PROPERTY_IS_TEST.equals(property)) { + return isJUnitTest(element); + } else if (PROPERTY_CAN_LAUNCH_AS_JUNIT_TEST.equals(property)) { + return canLaunchAsJUnitTest(element); + } + throw new IllegalArgumentException( + String.format("Unknown test property '%s'", property)); //$NON-NLS-1$ + } + + private boolean canLaunchAsJUnitTest(IJavaElement element) { + try { + switch (element.getElementType()) { + case IJavaElement.JAVA_PROJECT: + return true; // can run, let JDT detect if there are tests + case IJavaElement.PACKAGE_FRAGMENT_ROOT: + return false; // not supported by Android test runner + case IJavaElement.PACKAGE_FRAGMENT: + return ((IPackageFragment) element).hasChildren(); + case IJavaElement.COMPILATION_UNIT: + case IJavaElement.CLASS_FILE: + case IJavaElement.TYPE: + case IJavaElement.METHOD: + return isJUnitTest(element); + default: + return false; + } + } catch (JavaModelException e) { + return false; + } + } + + /** + * Return whether the target resource is a JUnit test. + */ + private boolean isJUnitTest(IJavaElement element) { + try { + IType testType = null; + if (element instanceof ICompilationUnit) { + testType = (((ICompilationUnit) element)).findPrimaryType(); + } else if (element instanceof IClassFile) { + testType = (((IClassFile) element)).getType(); + } else if (element instanceof IType) { + testType = (IType) element; + } else if (element instanceof IMember) { + testType = ((IMember) element).getDeclaringType(); + } + if (testType != null && testType.exists()) { + return TestSearchEngine.isTestOrTestSuite(testType); + } + } catch (CoreException e) { + // ignore, return false + } + return false; + } +} diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/runtime/AndroidJUnitLaunchInfo.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/runtime/AndroidJUnitLaunchInfo.java index 89cad97ae..8ac80cab5 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/runtime/AndroidJUnitLaunchInfo.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/runtime/AndroidJUnitLaunchInfo.java @@ -15,35 +15,38 @@ */ package com.android.ide.eclipse.adt.launch.junit.runtime; -import org.eclipse.core.resources.IProject; - import com.android.ddmlib.IDevice; +import org.eclipse.core.resources.IProject; +import org.eclipse.debug.core.ILaunch; + /** * Contains info about Android JUnit launch */ public class AndroidJUnitLaunchInfo { private final IProject mProject; - private final String mTestPackage; + private final String mAppPackage; private final String mRunner; - private final boolean mDebugMode; - private final IDevice mDevice; - - public AndroidJUnitLaunchInfo(IProject project, String testPackage, String runner, - boolean debugMode, IDevice device) { + + private boolean mDebugMode = false; + private IDevice mDevice = null; + private String mTestPackage = null; + private String mTestClass = null; + private String mTestMethod = null; + private ILaunch mLaunch = null; + + public AndroidJUnitLaunchInfo(IProject project, String appPackage, String runner) { mProject = project; - mTestPackage = testPackage; + mAppPackage = appPackage; mRunner = runner; - mDebugMode = debugMode; - mDevice = device; } - + public IProject getProject() { return mProject; } - public String getTestPackage() { - return mTestPackage; + public String getAppPackage() { + return mAppPackage; } public String getRunner() { @@ -53,8 +56,80 @@ public class AndroidJUnitLaunchInfo { public boolean isDebugMode() { return mDebugMode; } + + public void setDebugMode(boolean debugMode) { + mDebugMode = debugMode; + } public IDevice getDevice() { return mDevice; } + + public void setDevice(IDevice device) { + mDevice = device; + } + + /** + * Specify to run all tests within given package. + * + * @param testPackage fully qualified java package + */ + public void setTestPackage(String testPackage) { + mTestPackage = testPackage; + } + + /** + * Return the package of tests to run. + * + * @return fully qualified java package. null if not specified. + */ + public String getTestPackage() { + return mTestPackage; + } + + /** + * Sets the test class to run. + * + * @param testClass fully qualfied test class to run + * Expected format: x.y.x.testclass + */ + public void setTestClass(String testClass) { + mTestClass = testClass; + } + + /** + * Returns the test class to run. + * + * @return fully qualfied test class to run. + * null if not specified. + */ + public String getTestClass() { + return mTestClass; + } + + /** + * Sets the test method to run. testClass must also be set. + * + * @param testMethod test method to run + */ + public void setTestMethod(String testMethod) { + mTestMethod = testMethod; + } + + /** + * Returns the test method to run. + * + * @return test method to run. null if not specified. + */ + public String getTestMethod() { + return mTestMethod; + } + + public ILaunch getLaunch() { + return mLaunch; + } + + public void setLaunch(ILaunch launch) { + mLaunch = launch; + } } diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/runtime/RemoteAdtTestRunner.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/runtime/RemoteAdtTestRunner.java index 0a6a3daee..962d76133 100755 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/runtime/RemoteAdtTestRunner.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/junit/runtime/RemoteAdtTestRunner.java @@ -69,8 +69,9 @@ public class RemoteAdtTestRunner extends RemoteTestRunner { * executing the tests, and send it back to JDT JUnit. The second is the actual test execution, * whose results will be communicated back in real-time to JDT JUnit. * - * @param testClassNames array of fully qualified test class names to execute. Cannot be empty. - * @param testName test to execute. If null, will be ignored. + * @param testClassNames ignored - the AndroidJUnitLaunchInfo will be used to determine which + * tests to run. + * @param testName ignored * @param execution used to report test progress */ @Override @@ -78,16 +79,21 @@ public class RemoteAdtTestRunner extends RemoteTestRunner { // hold onto this execution reference so it can be used to report test progress mExecution = execution; - RemoteAndroidTestRunner runner = new RemoteAndroidTestRunner(mLaunchInfo.getTestPackage(), + RemoteAndroidTestRunner runner = new RemoteAndroidTestRunner(mLaunchInfo.getAppPackage(), mLaunchInfo.getRunner(), mLaunchInfo.getDevice()); - if (testClassNames != null && testClassNames.length > 0) { - if (testName != null) { - runner.setMethodName(testClassNames[0], testName); - } else { - runner.setClassNames(testClassNames); - } + if (mLaunchInfo.getTestClass() != null) { + if (mLaunchInfo.getTestMethod() != null) { + runner.setMethodName(mLaunchInfo.getTestClass(), mLaunchInfo.getTestMethod()); + } else { + runner.setClassName(mLaunchInfo.getTestClass()); + } } + + if (mLaunchInfo.getTestPackage() != null) { + runner.setTestPackageName(mLaunchInfo.getTestPackage()); + } + // set log only to first collect test case info, so Eclipse has correct test case count/ // tree info runner.setLogOnly(true); From 8a2dece67d273e16565bee8d8d952bde0ea5b982 Mon Sep 17 00:00:00 2001 From: Raphael Moll <> Date: Wed, 1 Apr 2009 12:29:32 -0700 Subject: [PATCH 18/45] AI 144048: ADT #1743364: Uncomment the system resource chooser code. Rationale: we want to keep that code around, so we need to compile it to make sure it doesn't use obsoleted APIs. That does it. BUG=1743364 Automated import of CL 144048 --- .../ide/eclipse/adt/ui/ResourceChooser.java | 63 ++++++++++--------- 1 file changed, 34 insertions(+), 29 deletions(-) diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/ui/ResourceChooser.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/ui/ResourceChooser.java index 4290f6b79..26396116c 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/ui/ResourceChooser.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/ui/ResourceChooser.java @@ -20,6 +20,10 @@ import com.android.ide.eclipse.common.resources.IResourceRepository; import com.android.ide.eclipse.common.resources.ResourceItem; import com.android.ide.eclipse.common.resources.ResourceType; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; +import org.eclipse.swt.events.SelectionEvent; +import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Shell; @@ -39,11 +43,11 @@ public class ResourceChooser extends AbstractElementListSelectionDialog { private IResourceRepository mProjectResources; - // TODO: enable when we can display the system resources. - // private Pattern mSystemResourcePattern; - // private IResourceRepository mSystemResources; - // private Button mProjectButton; - // private Button mSystemButton; + private final static boolean SHOW_SYSTEM_RESOURCE = false; // TODO re-enable at some point + private Pattern mSystemResourcePattern; + private IResourceRepository mSystemResources; + private Button mProjectButton; + private Button mSystemButton; private String mCurrentResource; @@ -60,14 +64,15 @@ public class ResourceChooser extends AbstractElementListSelectionDialog { mResourceType = type; mProjectResources = project; - // TODO: enable when we can display the system resources. - // mSystemResources = system; mProjectResourcePattern = Pattern.compile( "@" + mResourceType.getName() + "/(.+)"); //$NON-NLS-1$ //$NON-NLS-2$ - // TODO: enable when we can display the system resources. - // mSystemResourcePattern = Pattern.compile( - // "@android:" + mResourceType.getName() + "/(.+)"); //$NON-NLS-1$ //$NON-NLS-2$ + + if (SHOW_SYSTEM_RESOURCE) { + mSystemResources = system; + mSystemResourcePattern = Pattern.compile( + "@android:" + mResourceType.getName() + "/(.+)"); //$NON-NLS-1$ //$NON-NLS-2$ + } setTitle("Resource Chooser"); setMessage(String.format("Choose a %1$s resource", @@ -89,8 +94,7 @@ public class ResourceChooser extends AbstractElementListSelectionDialog { ResourceItem item = (ResourceItem)elements[0]; mCurrentResource = mResourceType.getXmlString(item, - // TODO: enable when we can display the system resources. - false /*mSystemButton.getSelection()*/); + SHOW_SYSTEM_RESOURCE && mSystemButton.getSelection()); } } @@ -100,9 +104,7 @@ public class ResourceChooser extends AbstractElementListSelectionDialog { createMessageArea(top); - // TODO: enable when we can display the system resources. - // createButtons(top); - + createButtons(top); createFilterText(top); createFilteredList(top); @@ -115,8 +117,10 @@ public class ResourceChooser extends AbstractElementListSelectionDialog { * Creates the radio button to switch between project and system resources. * @param top the parent composite */ - /* TODO: enable when we can display the system resources. private void createButtons(Composite top) { + if (!SHOW_SYSTEM_RESOURCE) { + return; + } mProjectButton = new Button(top, SWT.RADIO); mProjectButton.setText("Project Resources"); mProjectButton.addSelectionListener(new SelectionAdapter() { @@ -136,7 +140,6 @@ public class ResourceChooser extends AbstractElementListSelectionDialog { } }); } - */ /** * Setups the current list based on the current resource. @@ -147,20 +150,22 @@ public class ResourceChooser extends AbstractElementListSelectionDialog { ResourceItem[] items = mProjectResources.getResources(mResourceType); setListElements(items); } - /* - * TODO: enable when we can display the system resources. - if (setupInitialSelection(mProjectResourcePattern, mProjectResources) == false) { - if (setupInitialSelection(mSystemResourcePattern, mSystemResources) == false) { - // if we couldn't understand the current value, we default to the project resources - IResourceItem[] items = mProjectResources.getResources(mResourceType); - setListElements(items); - mProjectButton.setSelection(true); + + if (SHOW_SYSTEM_RESOURCE) { + if (setupInitialSelection(mProjectResourcePattern, mProjectResources) == false) { + if (setupInitialSelection(mSystemResourcePattern, mSystemResources) == false) { + // if we couldn't understand the current value, + // we default to the project resources + ResourceItem[] items = mProjectResources.getResources(mResourceType); + setListElements(items); + mProjectButton.setSelection(true); + } else { + mSystemButton.setSelection(true); + } } else { - mSystemButton.setSelection(true); + mProjectButton.setSelection(true); } - } else { - mProjectButton.setSelection(true); - }*/ + } } /** From dfa5494492fbab008a932a116cc74553e27ab941 Mon Sep 17 00:00:00 2001 From: Mike Ritter <> Date: Wed, 1 Apr 2009 17:30:12 -0700 Subject: [PATCH 19/45] AI 144164: Adding droiddocs/javadocs usage to Pdk-docs to get correct style. BUG=1646802 Automated import of CL 144164 --- pdk/Pdk.mk | 72 +++- pdk/README | 106 +++-- pdk/docs/audio_sub_system.html | 261 ------------ pdk/docs/audio_sub_system.jd | 56 +++ pdk/docs/bluetooth.html | 276 ------------- pdk/docs/bluetooth.jd | 82 ++++ pdk/docs/{bring_up.html => bring_up.jd} | 207 +--------- pdk/docs/build_new_device.html | 333 --------------- pdk/docs/build_new_device.jd | 130 ++++++ .../{build_system.html => build_system.jd} | 210 +--------- pdk/docs/camera.html | 280 ------------- pdk/docs/camera.jd | 87 ++++ ...isplay_drivers.html => display_drivers.jd} | 210 +--------- pdk/docs/getting_source_code.html | 335 ---------------- pdk/docs/getting_source_code.jd | 126 ++++++ pdk/docs/gps.html | 259 ------------ pdk/docs/gps.jd | 49 +++ .../{group__memory.html => group__memory.jd} | 25 +- ...__networking.html => group__networking.jd} | 26 +- pdk/docs/index.html | 248 ------------ pdk/docs/index.jd | 39 ++ ...work.html => instrumentation_framework.jd} | 181 +-------- ...esting.html => instrumentation_testing.jd} | 211 +--------- pdk/docs/intro_source_code.html | 378 ------------------ pdk/docs/intro_source_code.jd | 169 ++++++++ ...d_input.html => keymaps_keyboard_input.jd} | 210 +--------- pdk/docs/power_management.html | 311 -------------- pdk/docs/power_management.jd | 108 +++++ pdk/docs/source_setup_guide.html | 323 --------------- pdk/docs/source_setup_guide.jd | 116 ++++++ pdk/docs/system_requirements.html | 262 ------------ pdk/docs/system_requirements.jd | 63 +++ pdk/docs/{telephony.html => telephony.jd} | 211 +--------- pdk/docs/wifi.html | 250 ------------ pdk/docs/wifi.jd | 49 +++ pdk/hosting/app.yaml | 4 +- pdk/hosting/pdk.py | 18 +- 37 files changed, 1238 insertions(+), 5043 deletions(-) delete mode 100755 pdk/docs/audio_sub_system.html create mode 100755 pdk/docs/audio_sub_system.jd delete mode 100755 pdk/docs/bluetooth.html create mode 100755 pdk/docs/bluetooth.jd rename pdk/docs/{bring_up.html => bring_up.jd} (66%) delete mode 100755 pdk/docs/build_new_device.html create mode 100755 pdk/docs/build_new_device.jd rename pdk/docs/{build_system.html => build_system.jd} (62%) delete mode 100755 pdk/docs/camera.html create mode 100755 pdk/docs/camera.jd rename pdk/docs/{display_drivers.html => display_drivers.jd} (61%) delete mode 100755 pdk/docs/getting_source_code.html create mode 100755 pdk/docs/getting_source_code.jd delete mode 100755 pdk/docs/gps.html create mode 100755 pdk/docs/gps.jd rename pdk/docs/{group__memory.html => group__memory.jd} (54%) rename pdk/docs/{group__networking.html => group__networking.jd} (57%) delete mode 100755 pdk/docs/index.html create mode 100644 pdk/docs/index.jd rename pdk/docs/{instrumentation_framework.html => instrumentation_framework.jd} (50%) rename pdk/docs/{instrumentation_testing.html => instrumentation_testing.jd} (77%) delete mode 100755 pdk/docs/intro_source_code.html create mode 100755 pdk/docs/intro_source_code.jd rename pdk/docs/{keymaps_keyboard_input.html => keymaps_keyboard_input.jd} (71%) delete mode 100755 pdk/docs/power_management.html create mode 100755 pdk/docs/power_management.jd delete mode 100755 pdk/docs/source_setup_guide.html create mode 100755 pdk/docs/source_setup_guide.jd delete mode 100755 pdk/docs/system_requirements.html create mode 100755 pdk/docs/system_requirements.jd rename pdk/docs/{telephony.html => telephony.jd} (61%) delete mode 100755 pdk/docs/wifi.html create mode 100755 pdk/docs/wifi.jd diff --git a/pdk/Pdk.mk b/pdk/Pdk.mk index abe9491d2..fbe8b5c90 100644 --- a/pdk/Pdk.mk +++ b/pdk/Pdk.mk @@ -16,7 +16,7 @@ # Assemble the Platform Development Kit (PDK) # (TODO) Figure out why $(ACP) builds with target ndk but not pdk_docs -# (TODO) Build doxygen (depend on latest version) +# (TODO) Build doxygen (depend on latest version) -> line 25 error pdk: @echo "Package: $@ has targets ndk, pdk_docs and pdk_all" @@ -38,6 +38,8 @@ include $(LOCAL_PATH)/ndk/Ndk.mk # Doxygenize the header files to create html docs in the generatedDocs dir. # Copy the appengine files, the template files and the generated html # to the docs dir and zip everything up to the distribution directory. +# Run javadocs/droiddocs/clearsilver on the generatedDocs dir to get the right +# styles added to the html. # Workspace directory @@ -149,13 +151,27 @@ $(pdk_docs_intermediates)/pdk.py: $(pdk_hosting_dir)/pdk.py @echo "PDK: $@" $(copy-file-to-target-with-cp) +# Copy appengine server files for new system +$(OUT_DOCS)/app.yaml: $(pdk_hosting_dir)/app.yaml + @echo "PDK: $@" + $(copy-file-to-target-with-cp) + +$(OUT_DOCS)/pdk.py: $(pdk_hosting_dir)/pdk.py + @echo "PDK: $@" + $(copy-file-to-target-with-cp) + +# All the files that we depend upon +all_pdk_docs_files := $(pdk_doxygen_config_override_file) \ + $(pdk_doxygen_config_file) $(pdk_docs_intermediates)/header.html \ + $(pdk_docs_intermediates)/footer.html $(pdk_doxy_docsfiles_dir)/groups.dox \ + $(pdk_doxy_docsfiles_dir)/main.dox all_copied_pdk_templates # Run doxygen and copy all output and templates to the final destination # We replace index.html with a template file so don't use the generated one pdk_doxygen: all_copied_pdk_headers $(pdk_doxygen_config_override_file) \ $(pdk_doxygen_config_file) $(pdk_docs_intermediates)/header.html \ $(pdk_docs_intermediates)/footer.html $(pdk_doxy_docsfiles_dir)/groups.dox \ - $(pdk_doxy_docsfiles_dir)/main.dox + $(pdk_doxy_docsfiles_dir)/main.dox @echo "Files for Doxygination: $^" @mkdir -p $(pdk_generated_source_dir) @rm -f $(pdk_generated_source_dir)/* @@ -164,7 +180,40 @@ pdk_doxygen: all_copied_pdk_headers $(pdk_doxygen_config_override_file) \ @cd $(pdk_generated_source_dir) && chmod ug+rx * @rm -f $(pdk_generated_source_dir)/index.html @cp -fp $(pdk_generated_source_dir)/* $(pdk_docs_dest_dir) - + + +# ==== docs for the web (on the google app engine server) ======================= +# Run javadoc/droiddoc/clearsilver to get the formatting right + +# make droiddocs run after we make our doxygen docs +$(pdk_docs_intermediates)/pdk-timestamp: pdk_doxygen + @touch $(pdk_docs_intermediates)/pdk-timestamp + +$(LOCAL_PATH)/pdk-timestamp: $(pdk_docs_intermediates)/pdk-timestamp + +include $(CLEAR_VARS) + +LOCAL_SRC_FILES := pdk-timestamp samples/samplejni/src/com/example/jniexample/JNIExample.java +LOCAL_MODULE_CLASS := development/pdk/ndk/samples/samplejni/src/com/example/jniexample +LOCAL_DROIDDOC_SOURCE_PATH := $(framework_docs_LOCAL_DROIDDOC_SOURCE_PATH) +LOCAL_DROIDDOC_HTML_DIR := ../../../$(pdk_docs_dest_dir) + +LOCAL_MODULE := online-pdk + +LOCAL_DROIDDOC_OPTIONS := \ + $(framework_docs_LOCAL_DROIDDOC_OPTIONS) \ + $(web_docs_sample_code_flags) \ + -toroot /online-pdk/ \ + -hdf android.whichdoc online-pdk + +LOCAL_DROIDDOC_CUSTOM_TEMPLATE_DIR := build/tools/droiddoc/templates-pdk +LOCAL_DROIDDOC_CUSTOM_ASSET_DIR := assets-pdk + +include $(BUILD_DROIDDOC) + +# The docs output dir is: out/target/common/docs/online-pdk +DOCS_OUT_DIR := $(OUT_DOCS)/$(LOCAL_MODULE) + # Name the tar files name := android_pdk_docs-$(REQUESTED_PRODUCT) ifeq ($(TARGET_BUILD_TYPE),debug) @@ -173,21 +222,25 @@ endif name := $(name)-$(BUILD_NUMBER) pdk_docs_tarfile := $(pdk_docs_intermediates)/$(name).tar pdk_docs_tarfile_zipped := $(pdk_docs_tarfile).gz +new_pdk_docs_tarfile := $(pdk_docs_intermediates)/new-$(name).tar +new_pdk_docs_tarfile_zipped := $(new_pdk_docs_tarfile).gz -.PHONY: pdk pdk_docs pdk_doxygen all_copied_pdk_headers all_copied_pdk_templates +.PHONY: pdk pdk_docs pdk_doxygen all_copied_pdk_headers all_copied_pdk_templates pdk-timestamp -pdk_docs: $(pdk_docs_tarfile_zipped) +pdk_docs: $(pdk_docs_tarfile_zipped) $(new_pdk_docs_tarfile) @echo "PDK: Docs tarred and zipped" # Put the pdk_docs zip files in the distribution directory $(call dist-for-goals,pdk_docs,$(pdk_docs_tarfile_zipped)) +$(call dist-for-goals,pdk_docs,$(new_pdk_docs_tarfile_zipped)) # zip up tar files %.tar.gz: %.tar - @echo "PDK: zipped $<" + @echo "PDK docs: zipped $<" $(hide) gzip -cf $< > $@ # tar up all the files to make the pdk docs. +# old version $(pdk_docs_tarfile): pdk_doxygen all_copied_pdk_templates \ $(pdk_docs_intermediates)/pdk.py $(pdk_docs_intermediates)/app.yaml @echo "PDK: $@" @@ -195,6 +248,13 @@ $(pdk_docs_tarfile): pdk_doxygen all_copied_pdk_templates \ @rm -f $@ $(hide) tar rf $@ -C $(pdk_docs_intermediates) docs pdk.py app.yaml +# new version +$(new_pdk_docs_tarfile): $(DOCS_OUT_DIR)-timestamp + @echo "PDK docs: $@" + @mkdir -p $(dir $@) + @rm -f $@ + $(hide) tar rf $@ -C $(OUT_DOCS) $(LOCAL_MODULE) + # Debugging reporting can go here, add it as a target to get output. pdk_debug: @echo "You are here: $@" diff --git a/pdk/README b/pdk/README index 86621552e..18ff5d120 100644 --- a/pdk/README +++ b/pdk/README @@ -4,78 +4,72 @@ Building the pdk (platform development kit) (We currently support version 1.4.6) sudo apt-get install doxygen + +Make sure that you are using the right version of java + + sudo update-java-alternatives -s java-1.5.0-sun + +If that doesn't work, go through the instructions on + + http://source.android.com/download again. + 2) from the root . build/envsetup.sh -3) run choosecombo - Build for the simulator or the device? - 1. Device - 2. Simulator - - Which would you like? [1] 1 - - - Build type choices are: - 1. release - 2. debug - - Which would you like? [1] 1 - - - Product choices are: - 0. emulator - 1. generic - 2. sim - 3. surf - You can also type the name of a product if you know it. - Which would you like? [generic] 1 - - - Variant choices are: - 1. user - 2. userdebug - 3. eng - Which would you like? [eng] 3 - - ============================================ - TARGET_PRODUCT=generic - TARGET_BUILD_VARIANT=eng - TARGET_SIMULATOR=false - TARGET_BUILD_TYPE=release - TARGET_ARCH=arm - HOST_ARCH=x86 - HOST_OS=linux - HOST_BUILD_TYPE=release - BUILD_ID= - ============================================ 4) mkdir dist mkdir logs - mkpdkcupcake.sh + +then build everything: -(which contains: + time make -j4 pdk pdk_all dist DIST_DIR=dist 2>&1 | tee logs/`date +%y%m%d-%H%M%S` -DT=`date +%y%m%d-%H%M%S` -time make -j4 pdk pdk_all dist DIST_DIR=dist 2>&1 | tee logs/$DT +so you can have a record of the build commands in the logs directory. -so you can see the results of the build in the logs directory.) 5) the pdk tar file is put in the dist directory. +6) the pdk-docs are in + + out/target + The build target 'pdk' brings in the pdk/ndk make files into the build system. - Then there are three targets: - pdk_docs - which builds the pdk documentation - ndk - which builds the native development kit (native compiler, linker, etc.) - pdk_all - which builds the above two targets + Then there are three targets: + pdk_docs - which builds just the pdk documentation + ndk - which builds the native development kit (native compiler, linker, etc.) + pdk_all - which builds the above two targets -for doxygen version changing you can pass in the variable: -doxygen_version='' +To chnage which version of doxygen runs you can pass in the variable: + doxygen_version='' on the make line. -------------------------------------------------------------------------------- -To host the pdk docs on appengine run: -/home/build/static/projects/apphosting/devtools/appcfg.py update pdk/ -where the pdk directory contains: pdk.py, app.yaml, and the docs directory, -all of which are tarred up by the Pdk.mk file when using the targer pdk_docs. +# Testing +You must install google appengine. See: http://code.google.com/appengine/downloads.html + +Here's the command to run the pdk-docs server locally: + python /dev_appserver.py --address 0.0.0.0 \ + /android/out/target/common/docs/online-pdk + +To verify it is working you can access it with a browser loacally on port 8080: + +http://localhost:8080/index.html +TODO: index.html needs correct links. +TODO: app.yaml not working for redirecting, getting extra '.' in html names... + + -------------------------------------------------------------------------------- +# Deployment +To host the pdk docs on the interanl appengine run: +/home/build/static/projects/apphosting/devtools/appcfg.py update /out/common/docs +where the docs directory contains: pdk.py, app.yaml, and the online-pdk directory, +all of which are tarred up by the Pdk.mk file when using the target pdk_docs. + +# Deployment +To host the pdk docs on the external appengine run: +/home/build/static/projects/apphosting/devtools/appcfg.py -s pdk-docs.appspot.com update /out/common/docs +where the docs directory contains: pdk.py, app.yaml, and the online-pdk directory, +all of which are tarred up by the Pdk.mk file when using the target pdk_docs. + + diff --git a/pdk/docs/audio_sub_system.html b/pdk/docs/audio_sub_system.html deleted file mode 100755 index 8639cf0b1..000000000 --- a/pdk/docs/audio_sub_system.html +++ /dev/null @@ -1,261 +0,0 @@ - - - - -Android - Porting Guide - - - - - - - - - - - - - - - - -

- - -
- - -
-
- - - -
- -
- -
- -
- -

Android Platform Development Kit

- -
- -
- -
- -
- -
-
- - -

Introduction

- -

AudioHardwareInterface serves as the glue between proprietary audio drivers and the Android AudioFlinger service, the core audio service that handles all audio-related requests from applications.

-

- -Solid elements represent Android blocks and dashed elements represent partner-specific blocks. - - - -

Building an Audio Library

- -

To implement an audio driver, create a shared library that implements the interface defined in AudioHardwareInterface.h. You must name your shared library libaudio.so so that it will get loaded from /system/lib at runtime. Place libaudio sources and Android.mk in partner/acme/chipset_or_board/libaudio/.

-

The following stub Android.mk file ensures that libaudio compiles and links to the appropriate libraries:

- -
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libaudio
-
-LOCAL_SHARED_LIBRARIES := \
-    libcutils \
-    libutils \
-    libmedia \
-    libhardware
-
-LOCAL_SRC_FILES += MyAudioHardware.cpp
-
-LOCAL_CFLAGS +=
-
-LOCAL_C_INCLUDES +=
-
-LOCAL_STATIC_LIBRARIES += libaudiointerface
-
-include $(BUILD_SHARED_LIBRARY)
-
- - -

Interface

- - - -

Note: This document relies on some Doxygen-generated content that appears in an iFrame below. To return to the Doxygen default content for this page, click here.

- - - - - -

- -

-
- -
- -
- - - -
- - - -
v0.6 - 25 November 2008
- - - diff --git a/pdk/docs/audio_sub_system.jd b/pdk/docs/audio_sub_system.jd new file mode 100755 index 000000000..903032fad --- /dev/null +++ b/pdk/docs/audio_sub_system.jd @@ -0,0 +1,56 @@ +page.title=Audio +pdk.version=1.0 +@jd:body + + +
+Introduction
+Building an Audio Library
+Interface
+ +

Introduction

+ +

AudioHardwareInterface serves as the glue between proprietary audio drivers and the Android AudioFlinger service, the core audio service that handles all audio-related requests from applications.

+

+ +Solid elements represent Android blocks and dashed elements represent partner-specific blocks. + + + +

Building an Audio Library

+ +

To implement an audio driver, create a shared library that implements the interface defined in AudioHardwareInterface.h. You must name your shared library libaudio.so so that it will get loaded from /system/lib at runtime. Place libaudio sources and Android.mk in partner/acme/chipset_or_board/libaudio/.

+

The following stub Android.mk file ensures that libaudio compiles and links to the appropriate libraries:

+ +
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libaudio
+
+LOCAL_SHARED_LIBRARIES := \
+    libcutils \
+    libutils \
+    libmedia \
+    libhardware
+
+LOCAL_SRC_FILES += MyAudioHardware.cpp
+
+LOCAL_CFLAGS +=
+
+LOCAL_C_INCLUDES +=
+
+LOCAL_STATIC_LIBRARIES += libaudiointerface
+
+include $(BUILD_SHARED_LIBRARY)
+
+ + +

Interface

+ + + +

Note: This document relies on some Doxygen-generated content that appears in an iFrame below. To return to the Doxygen default content for this page, click here.

+ + + diff --git a/pdk/docs/bluetooth.html b/pdk/docs/bluetooth.html deleted file mode 100755 index edd3c260d..000000000 --- a/pdk/docs/bluetooth.html +++ /dev/null @@ -1,276 +0,0 @@ - -

- - - - -Android - Porting Guide - - - - - - - - - - - - - - - - -

- - -
- - -
-
- - - -
- -
- -
- -
- -

Android Platform Development Kit

- -
- -
- -
- -
- -
-
- - -

Introduction

- -

Android's Bluetooth stack uses BlueZ version 3.36 for GAP, SDP, and RFCOMM profiles, and is a SIG-qualified Bluetooth 2.0 host stack.

- -

Bluez is GPL licensed, so the Android framework interacts with userspace bluez code through D-BUS IPC to avoid proprietary code.

- -

Headset and Handsfree (v1.5) profiles are implemented in the Android framework and are both tightly coupled with the Phone App. These profiles are also SIG qualified.

- -

The diagram below offers a library-oriented view of the Bluetooth stack. Click Bluetooth Process Diagram for a process-oriented view.

- -

- -Solid elements represent Android blocks and dashed elements represent partner-specific blocks. - - - -

Porting

- -

BlueZ is Bluetooth 2.0 compatible and should work with any 2.0 chipset. There are two integration points:

-

    -
  • UART driver
  • -
  • Bluetooth Power On / Off
  • -
-

- - -

UART Driver

- -

The BlueZ kernel sub-system attaches to your hardware-specific UART driver using the hciattach daemon.

-

For example, for MSM7201A, this is drivers/serial/msm_serial.c. You may also need to edit command line options to hciattach via init.rc.

- - -

Bluetooth Power On / Off

- -

The method for powering on and off your bluetooth chip varies from Android V 1.0 to post 1.0.

- -

    -
  • 1.0: Android framework writes a 0 or 1 to /sys/modules/board_[PLATFORM]/parameters/bluetooth_power_on.
  • - -
  • Post 1.0: Android framework uses the linux rfkill API. See arch/arm/mach-msm/board-trout-rfkill.c for an example.
  • -
-

- - -

Tools

- -

BlueZ provides a rich set of command line tools for debugging and interacting with the Bluetooth sub-system, including:

-

    -
  • hciconfig
  • -
  • hcitool
  • -
  • hcidump
  • -
  • sdptool
  • -
  • dbus-send
  • -
  • dbus-monitor
  • -
-

- - -

- -

-
- -
- -
- - - -
- - - -
v0.6 - 25 November 2008
- - - diff --git a/pdk/docs/bluetooth.jd b/pdk/docs/bluetooth.jd new file mode 100755 index 000000000..a21ad7dea --- /dev/null +++ b/pdk/docs/bluetooth.jd @@ -0,0 +1,82 @@ +page.title=Bluetooth +@jd:body + +
+
+ + +

In this document

+ +
    +
  1. Introduction
  2. +
  3. Porting +
      +
    1. UART Driver
    2. +
    3. Bluetooth Power On / Off
    4. +
    +
  4. +
  5. Tools
  6. +
+ +
+
+ +

Introduction

+ +

Android's Bluetooth stack uses BlueZ version 3.36 for GAP, SDP, and RFCOMM profiles, and is a SIG-qualified Bluetooth 2.0 host stack.

+ +

Bluez is GPL licensed, so the Android framework interacts with userspace bluez code through D-BUS IPC to avoid proprietary code.

+ +

Headset and Handsfree (v1.5) profiles are implemented in the Android framework and are both tightly coupled with the Phone App. These profiles are also SIG qualified.

+ +

The diagram below offers a library-oriented view of the Bluetooth stack. Click Bluetooth Process Diagram for a process-oriented view.

+ +

+ +Solid elements represent Android blocks and dashed elements represent partner-specific blocks. + + + +

Porting

+ +

BlueZ is Bluetooth 2.0 compatible and should work with any 2.0 chipset. There are two integration points:

+

+

+ + +

UART Driver

+ +

The BlueZ kernel sub-system attaches to your hardware-specific UART driver using the hciattach daemon.

+

For example, for MSM7201A, this is drivers/serial/msm_serial.c. You may also need to edit command line options to hciattach via init.rc.

+ + +

Bluetooth Power On / Off

+ +

The method for powering on and off your bluetooth chip varies from Android V 1.0 to post 1.0.

+ +

+

+ + +

Tools

+ +

BlueZ provides a rich set of command line tools for debugging and interacting with the Bluetooth sub-system, including:

+

+

+ + + diff --git a/pdk/docs/bring_up.html b/pdk/docs/bring_up.jd similarity index 66% rename from pdk/docs/bring_up.html rename to pdk/docs/bring_up.jd index b70a35dd5..763f85e36 100755 --- a/pdk/docs/bring_up.html +++ b/pdk/docs/bring_up.jd @@ -1,184 +1,12 @@ - - - - -Android - Porting Guide - - - - - - - - - - - - - - - - -
- - -
- - -
-
- - - -
- -
- -
- -
- -

Android Platform Development Kit

- -
- -
- -
- -
- -
-
-
- - -

Bring Up

+page.title=Bring Up +@jd:body

Once your code is built and you have verified that all necessary directories exist, power on and test your device with basic bring up, as described below. Bring up tests are typically designed to stress certain aspects of your system and allow you to characterize the device's behavior.

 

1. Confirm a Clean Installation of a Basic Linux Kernel

Before considering Android-specific modifications to the Linux kernel, verify that you can build, deploy, and boot a core Linux kernel on your target hardware.

 

+

2. Modify Your Kernel Configuration to Accommodate Android Drivers

Your kernel configuration file should include the following:

@@ -530,32 +358,3 @@ service akmd /sbin/akmd
 
-

- -

-
- -
- -
- - - -
- - - -
v0.6 - 25 November 2008
-
- - diff --git a/pdk/docs/build_new_device.html b/pdk/docs/build_new_device.html deleted file mode 100755 index cbf9ed7a5..000000000 --- a/pdk/docs/build_new_device.html +++ /dev/null @@ -1,333 +0,0 @@ - - - - -Android - Porting Guide - - - - - - - - - - - - - - - - -
- - -
- - -
-
- - - -
- -
- -
- -
- -

Android Platform Development Kit

- -
- -
- -
- -
- -
-
-
- - -

Building Android for a new Mobile Device

- - - - -
- -

Detailed Instructions

- -

The directions below describe how to configure make files for new mobile devices and products.

-
    -
  1. Create a company directory in //device/partner.
    -
    -  mkdir device/partner/<company_name>
  2. -
  3. Create a products directory beneath the company directory you created in step 1.
    -
    -  mkdir device/partner/<company_name>/products/
  4. -
  5. Create a product-specific make file, called device/partner/<company_name>/products/<first_product_name>.mk, that includes the following code:
    -
    -  $(call inherit-product, target/product/generic.mk)
    -  #
    -  # Overrides
    -  PRODUCT_NAME := <first_product_name>
    -  PRODUCT_DEVICE := <board_name>
  6. -
  7. In the products directory, create an AndroidProducts.mk file that point to (and is responsible for finding) the individual product make files.
    -
    -  #
    -  # This file should set PRODUCT_MAKEFILES to a list of product makefiles
    -  # to expose to the build system.  LOCAL_DIR will already be set to
    -  # the directory containing this file. 
    -  #
    -  # This file may not rely on the value of any variable other than
    -  # LOCAL_DIR; do not use any conditionals, and do not look up the
    -  # value of any variable that isn't set in this file or in a file that
    -  # it includes.
    -  #
    -  
    -  PRODUCT_MAKEFILES := \
    -    $(LOCAL_DIR)/first_product_name.mk \
  8. -
  9. Create a board-specific directory beneath your company directory that matches the PRODUCT_DEVICE variable <board_name> referenced in the product-specific make file above. This will include a make file that gets accessed by any product using this board.
    -
    -  mkdir device/partner/<company_name>/<board_name>
  10. -
  11. Create a product_config.mk file in the directory created in the previous step (device/partner/<company_name>/<board_name>). If this directory does not include a product_config.mk file, the build will fail.
    -
    -  # These definitions override the defaults in config/config.make for <board_name>
    -  #
    -  # TARGET_NO_BOOTLOADER := false
    -  # TARGET_HARDWARE_3D := false 
    -  #
    -  TARGET_USE_GENERIC_AUDIO := true
  12. -
  13. If you wish to modify system properties, create a system.prop file in your <board_name> directory(device/partner/<company_name>/<board_name>).
    -
    -  # system.prop for 
    -  # This overrides settings in the products/generic/system.prop file
    -  #
    -  # rild.libpath=/system/lib/libreference-ril.so
    -  # rild.libargs=-d /dev/ttyS0
  14. -
  15. Add a pointer to <second_product_name>.mk within products/AndroidProducts.mk.
    -
    -  PRODUCT_MAKEFILES := \
    -    $(LOCAL_DIR)/first_product_name.mk \
    -    $(LOCAL_DIR)/second_product_name.mk
  16. -
  17. device/partner/<company_name>/<board_name> must include an Android.mk file with at least the following code:

    -
    -  # make file for new hardware  from 
    -  #
    -  LOCAL_PATH := $(call my-dir)
    -  #
    -  # this is here to use the pre-built kernel
    -  ifeq ($(TARGET_PREBUILT_KERNEL),)
    -  TARGET_PREBUILT_KERNEL := $(LOCAL_PATH)/kernel
    -  endif
    -  #
    -  file := $(INSTALLED_KERNEL_TARGET)
    -  ALL_PREBUILT += $(file)
    -  $(file): $(TARGET_PREBUILT_KERNEL) | $(ACP)
    -		$(transform-prebuilt-to-target)
    -  #
    -  # no boot loader, so we don't need any of that stuff..  
    -  #
    -  LOCAL_PATH := partner/<company_name>/<board_name>
    -  #
    -  include $(CLEAR_VARS)
    -  #
    -  # include more board specific stuff here? Such as Audio parameters.      
    -  #
  18. -
  19. To create a second product for the same board, create a second product-specific make file called device/partner/company_name/products/<second_product_name>.mk that includes:
    -
    -  $(call inherit-product, partner/google/products/generic.mk)
    -  #
    -  # Overrides
    -  PRODUCT_NAME := <second_product_name>
    -  PRODUCT_DEVICE := <board_name>
  20. -
-

By now, you should have two new products, called <first_product_name> and <second_product_name> associated with <company_name>. To verify that a product is properly configured (<first_product_name>, for example), execute the following:
-

-  cd device
-  . ./envsetup.sh
-  partner_setup <first_product_name>
-  make PRODUCT-<first_product_name>-user
-
-

You should find new build binaries located in device/out/target/product/<board_name>. - - -

New Product File Tree

- -

The file tree below illustrates what your own system should look like after completing the steps above.

-

-

    -
  • <company_name>
  • -
      -
    • <board_name>
    • -
        -
      • Android.mk
      • -
      • product_config.mk
      • -
      • system.prop
      • -
      -
    • products
    • -
        -
      • AndroidProducts.mk
      • -
      • <first_product_name>.mk
      • -
      • <second_product_name>.mk
      • -
      -
    -
-

- - -

- -

-
- -
- -
- - - -
- - - -
v0.6 - 25 November 2008
- - - diff --git a/pdk/docs/build_new_device.jd b/pdk/docs/build_new_device.jd new file mode 100755 index 000000000..f0a816f54 --- /dev/null +++ b/pdk/docs/build_new_device.jd @@ -0,0 +1,130 @@ +page.title=Building Android for a new Mobile Device +pdk.version=1.0 +@jd:body + + + + +
+Detailed Instructions
+New Product File Tree
+ +

Detailed Instructions

+ +

The directions below describe how to configure make files for new mobile devices and products.

+
    +
  1. Create a company directory in //device/partner.
    +
    +  mkdir device/partner/<company_name>
  2. +
  3. Create a products directory beneath the company directory you created in step 1.
    +
    +  mkdir device/partner/<company_name>/products/
  4. +
  5. Create a product-specific make file, called device/partner/<company_name>/products/<first_product_name>.mk, that includes the following code:
    +
    +  $(call inherit-product, target/product/generic.mk)
    +  #
    +  # Overrides
    +  PRODUCT_NAME := <first_product_name>
    +  PRODUCT_DEVICE := <board_name>
  6. +
  7. In the products directory, create an AndroidProducts.mk file that point to (and is responsible for finding) the individual product make files.
    +
    +  #
    +  # This file should set PRODUCT_MAKEFILES to a list of product makefiles
    +  # to expose to the build system.  LOCAL_DIR will already be set to
    +  # the directory containing this file. 
    +  #
    +  # This file may not rely on the value of any variable other than
    +  # LOCAL_DIR; do not use any conditionals, and do not look up the
    +  # value of any variable that isn't set in this file or in a file that
    +  # it includes.
    +  #
    +  
    +  PRODUCT_MAKEFILES := \
    +    $(LOCAL_DIR)/first_product_name.mk \
  8. +
  9. Create a board-specific directory beneath your company directory that matches the PRODUCT_DEVICE variable <board_name> referenced in the product-specific make file above. This will include a make file that gets accessed by any product using this board.
    +
    +  mkdir device/partner/<company_name>/<board_name>
  10. +
  11. Create a product_config.mk file in the directory created in the previous step (device/partner/<company_name>/<board_name>). If this directory does not include a product_config.mk file, the build will fail.
    +
    +  # These definitions override the defaults in config/config.make for <board_name>
    +  #
    +  # TARGET_NO_BOOTLOADER := false
    +  # TARGET_HARDWARE_3D := false 
    +  #
    +  TARGET_USE_GENERIC_AUDIO := true
  12. +
  13. If you wish to modify system properties, create a system.prop file in your <board_name> directory(device/partner/<company_name>/<board_name>).
    +
    +  # system.prop for 
    +  # This overrides settings in the products/generic/system.prop file
    +  #
    +  # rild.libpath=/system/lib/libreference-ril.so
    +  # rild.libargs=-d /dev/ttyS0
  14. +
  15. Add a pointer to <second_product_name>.mk within products/AndroidProducts.mk.
    +
    +  PRODUCT_MAKEFILES := \
    +    $(LOCAL_DIR)/first_product_name.mk \
    +    $(LOCAL_DIR)/second_product_name.mk
  16. +
  17. device/partner/<company_name>/<board_name> must include an Android.mk file with at least the following code:

    +
    +  # make file for new hardware  from 
    +  #
    +  LOCAL_PATH := $(call my-dir)
    +  #
    +  # this is here to use the pre-built kernel
    +  ifeq ($(TARGET_PREBUILT_KERNEL),)
    +  TARGET_PREBUILT_KERNEL := $(LOCAL_PATH)/kernel
    +  endif
    +  #
    +  file := $(INSTALLED_KERNEL_TARGET)
    +  ALL_PREBUILT += $(file)
    +  $(file): $(TARGET_PREBUILT_KERNEL) | $(ACP)
    +		$(transform-prebuilt-to-target)
    +  #
    +  # no boot loader, so we don't need any of that stuff..  
    +  #
    +  LOCAL_PATH := partner/<company_name>/<board_name>
    +  #
    +  include $(CLEAR_VARS)
    +  #
    +  # include more board specific stuff here? Such as Audio parameters.      
    +  #
  18. +
  19. To create a second product for the same board, create a second product-specific make file called device/partner/company_name/products/<second_product_name>.mk that includes:
    +
    +  $(call inherit-product, partner/google/products/generic.mk)
    +  #
    +  # Overrides
    +  PRODUCT_NAME := <second_product_name>
    +  PRODUCT_DEVICE := <board_name>
  20. +
+

By now, you should have two new products, called <first_product_name> and <second_product_name> associated with <company_name>. To verify that a product is properly configured (<first_product_name>, for example), execute the following:
+

+  cd device
+  . ./envsetup.sh
+  partner_setup <first_product_name>
+  make PRODUCT-<first_product_name>-user
+
+

You should find new build binaries located in device/out/target/product/<board_name>. + + +

New Product File Tree

+ +

The file tree below illustrates what your own system should look like after completing the steps above.

+

+

+

diff --git a/pdk/docs/build_system.html b/pdk/docs/build_system.jd similarity index 62% rename from pdk/docs/build_system.html rename to pdk/docs/build_system.jd index 4286e71f0..b157f4dbc 100755 --- a/pdk/docs/build_system.html +++ b/pdk/docs/build_system.jd @@ -1,179 +1,6 @@ - - - - -Android - Porting Guide - - - - - - - - - - - - - - - - -
- - -
- - -
-
- - - -
- -
- -
- -
- -

Android Platform Development Kit

- -
- -
- -
- -
- -
-
-
- - -

Android Build System

- +page.title=Android Build System +pdk.version=1.0 +@jd:body @@ -425,34 +252,3 @@ Java HotSpot(TM) Client VM (build 1.5.0_07-87, mixed mode, sharing)
 % make -j4
 
- - -

- -

-
- -
- -
- - - -
- - - -
v0.6 - 25 November 2008
-
- - diff --git a/pdk/docs/camera.html b/pdk/docs/camera.html deleted file mode 100755 index 1b6565984..000000000 --- a/pdk/docs/camera.html +++ /dev/null @@ -1,280 +0,0 @@ - - - - -Android - Porting Guide - - - - - - - - - - - - - - - - -
- - -
- - -
-
- - - -
- -
- -
- -
- -

Android Platform Development Kit

- -
- -
- -
- -
- -
-
- - -

Introduction

- -

Android's camera subsystem connects the camera application to the application framework and user space libraries, which in turn communicate with the camera hardware layer that operates the physical camera.

-

The diagram below illustrates the structure of the camera subsystem.

-

- - -

Building a Camera Library

- -

To implement a camera driver, create a shared library that implements the interface defined in CameraHardwareInterface.h. You must name your shared library libcamera.so so that it will get loaded from /system/lib at runtime. Place libcamera sources and Android.mk in partner/acme/chipset_or_board/libcamera/.

-

The following stub Android.mk file ensures that libcamera compiles and links to the appropriate libraries:

-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libcamera
-
-LOCAL_SHARED_LIBRARIES := \
-    libutils \
-    librpc \
-    liblog
-
-LOCAL_SRC_FILES += MyCameraHardware.cpp
-
-LOCAL_CFLAGS +=
-
-LOCAL_C_INCLUDES +=
-
-LOCAL_STATIC_LIBRARIES += \
-    libcamera-common \
-    libclock-rpc \
-    libcommondefs-rpc
-
-include $(BUILD_SHARED_LIBRARY)
-
- - -

Sequence Diagrams

- - - -

Preview

- -

The following diagram illustrates the sequence of function calls and actions necessary for your camera to preview.

- - - -

Taking a Picture

- -

The following diagram illustrates the sequence of function calls and actions necessary for your camera to take a picture.

- - - -

Interface

- - - -

Note: This document relies on some Doxygen-generated content that appears in an iFrame below. To return to the Doxygen default content for this page, click here.

- - - - - -

- -

-
- -
- -
- - - -
- - - -
v0.6 - 25 November 2008
- - - diff --git a/pdk/docs/camera.jd b/pdk/docs/camera.jd new file mode 100755 index 000000000..85ed3dc4f --- /dev/null +++ b/pdk/docs/camera.jd @@ -0,0 +1,87 @@ +page.title=Camera Subsystem +@jd:body + +
+
+ + +

In this document

+ +
    +
  1. Introduction
  2. +
  3. Building a Camera Library
  4. +
  5. Sequence Diagrams +
      +
    1. Preview
    2. +
    3. Taking a Picture
    4. +
    +
  6. +
  7. Interface
  8. +
+ +
+
+ +

Introduction

+ +

Android's camera subsystem connects the camera application to the application framework and user space libraries, which in turn communicate with the camera hardware layer that operates the physical camera.

+

The diagram below illustrates the structure of the camera subsystem.

+

+ + +

Building a Camera Library

+ +

To implement a camera driver, create a shared library that implements the interface defined in CameraHardwareInterface.h. You must name your shared library libcamera.so so that it will get loaded from /system/lib at runtime. Place libcamera sources and Android.mk in partner/acme/chipset_or_board/libcamera/.

+

The following stub Android.mk file ensures that libcamera compiles and links to the appropriate libraries:

+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libcamera
+
+LOCAL_SHARED_LIBRARIES := \
+    libutils \
+    librpc \
+    liblog
+
+LOCAL_SRC_FILES += MyCameraHardware.cpp
+
+LOCAL_CFLAGS +=
+
+LOCAL_C_INCLUDES +=
+
+LOCAL_STATIC_LIBRARIES += \
+    libcamera-common \
+    libclock-rpc \
+    libcommondefs-rpc
+
+include $(BUILD_SHARED_LIBRARY)
+
+ + +

Sequence Diagrams

+ + + +

Preview

+ +

The following diagram illustrates the sequence of function calls and actions necessary for your camera to preview.

+ + + +

Taking a Picture

+ +

The following diagram illustrates the sequence of function calls and actions necessary for your camera to take a picture.

+ + + +

Interface

+ + + +

Note: This document relies on some Doxygen-generated content that appears in an iFrame below. To return to the Doxygen default content for this page, click here.

+ + + + + diff --git a/pdk/docs/display_drivers.html b/pdk/docs/display_drivers.jd similarity index 61% rename from pdk/docs/display_drivers.html rename to pdk/docs/display_drivers.jd index c20afe547..d1272079e 100755 --- a/pdk/docs/display_drivers.html +++ b/pdk/docs/display_drivers.jd @@ -1,187 +1,12 @@ - - - - -Android - Porting Guide - - - - - - - - - - - - - - - - -
- - -
- - -
-
- - - -
- -
- -
- -
- -

Android Platform Development Kit

- -
- -
- -
- -
- -
-
-
- - -

Display Drivers

- - +page.title=Display Drivers +@jd:body
+Troubleshooting

Introduction

@@ -513,32 +338,3 @@ MODULE_LICENSE("GPL");

Android relies on a double buffer to smoothly render page flips (please see Functionality for details). -

- -

-
- -
- -
- - - - - - - -
v0.6 - 25 November 2008
- - - diff --git a/pdk/docs/getting_source_code.html b/pdk/docs/getting_source_code.html deleted file mode 100755 index ad0cddbd4..000000000 --- a/pdk/docs/getting_source_code.html +++ /dev/null @@ -1,335 +0,0 @@ - - - - -Android - Porting Guide - - - - - - - - - - - - - - - - -
- - -
- - -
-
- - - -
- -
- -
- -
- -

Android Platform Development Kit

- -
- -
- -
- -
- -
-
- - -

Introduction

- -

Android relies on Git, a version control system, to install the Android platform. You will need to install Git 1.5.2 or greater in order to access the source tree. Please visit http://git.or.cz/ for more information regarding Git.

-

Git permits you to control access to working directories, and we recommend that you use it to limit Android repository access to only a few people within your organization (please refer to your Google NDA for potential contractual restraints on sharing Android source access).

-

You may clone Google's repository to a local copy for sharing internally (see Git documentation for details).

- - -

Installing and Configuring Git

- -

To install the Git package, execute:

-
-% sudo apt-get install git-core
-
- - -

Establishing Server Access

- -

Once Git is cleanly installed, you need to establish a connection with Google's Git server, a connection that requires an RSA key in order to authenticate requests.

- - -

Generating RSA Keys

- -

Each developer must have a unique RSA key in order to access Android source code. To generate an RSA key:

-

-

    -
  1. Type:
    -
    % ssh-keygen -t rsa -C  email@domain.com

    -You must use a valid email address to create your key.
  2. -
  3. When prompted, indicate the file to which you wish to write your key (id_rsa in this example).
  4. -
  5. When prompted, associate a passphrase with your key.
  6. -
  7. Upon success, you should have two files saved to the designated directory:
  8. -
      -
    • id_rsa: This file contains the private half of your RSA key. You shouldn't share this file with anyone.
    • -
    • id_rsa.pub: This is the public half or your RSA key and you should send it to your Google technical account manager.
    • -
    -
-

-

Send your Google Account Manager your public key file in order to establish Git server access.

- - -

Verifying a Connection to the Git Server

- -

Once you have generated an RSA key and shared the public file with Google, you can test your connection with the Git server with the following command:

-
-% ssh  android-git.ext.google.com
-
- -

You should receive one of the following results:

- - - - - - - - - - - - - - - - - - - - - - -
ResultCauseAction
-fatal: What do you think I am? A shell?
-Connection to android-git closed.
-
SuccessNone. You successfully connected to the Git server. (You should not have shell access and it's expected to receive this error.)
ssh hangs and eventually times out. Your setup is failing to locate and establish a basic connection. Google needs to debug network settings.
Error: Permission denied <public key> Either you are not using the matching username or the RSA private key does not match the public key. Try executing:
- -% ssh $USER@android- - git.ext.google.com -
- - -

Downloading Code

- -

Android source code is maintained in two repositories: device and kernel. The device repository includes the Android framework (things like the Activity Manager, Window Manager, Telephony Manager, View System, etc.). The kernel repository includes the core code necessary to run the operating system (things like the Display Driver, Camera Driver, Keypad Driver, Power Management, etc.). (Please see What is Android? for details.)

- -

Save device and kernel code at the same directory level, for example:

-

-

  • /home/joe/android/device
  • -
  • /home/joe/android/kernel
  • -

-

Device Code

-

To download device code, you need your username and a unique <path> string supplied by Google to execute the following:

-
-% git-clone $USER@android-git.ext.google.com:<path>/device.git
-
- -

Kernel Code

-

To download kernel code, you need your username and a unique <path> string supplied by Google to execute the following:

-
-% git-clone $USER@android-git.ext.google.com:<path>/kernel.git
-
- - - -

Extracting an Android Patch

- -

You likely already have Linux running on your platform and only need to integrate Android-specific changes. The following directions describe how to extract an Android patch.

-
    -
  1. Download a generic version of the Linux kernel that matches the Linux version downloaded with the Android Kernel code.
  2. -
  3. Run diff on the two kernel packages to get Android-specific changes.
  4. -
  5. Apply the patch to your target kernel and build.
  6. -
- - -

- -

-
- -
- -
- - - -
- - - -
v0.5 - 25 September 2008
- - - diff --git a/pdk/docs/getting_source_code.jd b/pdk/docs/getting_source_code.jd new file mode 100755 index 000000000..19a7069ab --- /dev/null +++ b/pdk/docs/getting_source_code.jd @@ -0,0 +1,126 @@ +page.title=Getting Source Code +@jd:body + + +
+Introduction
+Installing and Configuring Git
+Establishing Server Access
+ +Generating RSA Keys
+Verifying a Connection to the Git Server
+Downloading Code
+Extracting an Android Patch
+ +

Introduction

+ +

Android relies on Git, a version control system, to install the Android platform. You will need to install Git 1.5.2 or greater in order to access the source tree. Please visit http://git.or.cz/ for more information regarding Git.

+

Git permits you to control access to working directories, and we recommend that you use it to limit Android repository access to only a few people within your organization (please refer to your Google NDA for potential contractual restraints on sharing Android source access).

+

You may clone Google's repository to a local copy for sharing internally (see Git documentation for details).

+ + +

Installing and Configuring Git

+ +

To install the Git package, execute:

+
+% sudo apt-get install git-core
+
+ + +

Establishing Server Access

+ +

Once Git is cleanly installed, you need to establish a connection with Google's Git server, a connection that requires an RSA key in order to authenticate requests.

+ + +

Generating RSA Keys

+ +

Each developer must have a unique RSA key in order to access Android source code. To generate an RSA key:

+

+

    +
  1. Type:
    +
    % ssh-keygen -t rsa -C  email@domain.com

    +You must use a valid email address to create your key.
  2. +
  3. When prompted, indicate the file to which you wish to write your key (id_rsa in this example).
  4. +
  5. When prompted, associate a passphrase with your key.
  6. +
  7. Upon success, you should have two files saved to the designated directory:
  8. + +
+

+

Send your Google Account Manager your public key file in order to establish Git server access.

+ + +

Verifying a Connection to the Git Server

+ +

Once you have generated an RSA key and shared the public file with Google, you can test your connection with the Git server with the following command:

+
+% ssh  android-git.ext.google.com
+
+ +

You should receive one of the following results:

+ + + + + + + + + + + + + + + + + + + + + + +
ResultCauseAction
+fatal: What do you think I am? A shell?
+Connection to android-git closed.
+
SuccessNone. You successfully connected to the Git server. (You should not have shell access and it's expected to receive this error.)
ssh hangs and eventually times out. Your setup is failing to locate and establish a basic connection. Google needs to debug network settings.
Error: Permission denied <public key> Either you are not using the matching username or the RSA private key does not match the public key. Try executing:
+ +% ssh $USER@android- + git.ext.google.com +
+ + +

Downloading Code

+ +

Android source code is maintained in two repositories: device and kernel. The device repository includes the Android framework (things like the Activity Manager, Window Manager, Telephony Manager, View System, etc.). The kernel repository includes the core code necessary to run the operating system (things like the Display Driver, Camera Driver, Keypad Driver, Power Management, etc.). (Please see What is Android? for details.)

+ +

Save device and kernel code at the same directory level, for example:

+

+

+

Device Code

+

To download device code, you need your username and a unique <path> string supplied by Google to execute the following:

+
+% git-clone $USER@android-git.ext.google.com:<path>/device.git
+
+ +

Kernel Code

+

To download kernel code, you need your username and a unique <path> string supplied by Google to execute the following:

+
+% git-clone $USER@android-git.ext.google.com:<path>/kernel.git
+
+ + + +

Extracting an Android Patch

+ +

You likely already have Linux running on your platform and only need to integrate Android-specific changes. The following directions describe how to extract an Android patch.

+
    +
  1. Download a generic version of the Linux kernel that matches the Linux version downloaded with the Android Kernel code.
  2. +
  3. Run diff on the two kernel packages to get Android-specific changes.
  4. +
  5. Apply the patch to your target kernel and build.
  6. +
+ diff --git a/pdk/docs/gps.html b/pdk/docs/gps.html deleted file mode 100755 index eb5473fc1..000000000 --- a/pdk/docs/gps.html +++ /dev/null @@ -1,259 +0,0 @@ - - - - -Android - Porting Guide - - - - - - - - - - - - - - - - -
- - -
- - -
-
- - - -
- -
- -
- -
- -

Android Platform Development Kit

- -
- -
- -
- -
- -
-
- - -

Introduction

- -

Android defines a user space C abstraction interface for GPS hardware. The interface header is defined in include/hardware/gps.h. In order to integate GPS with Android, you need to build a shared library that implements this interface.

- - -

Building a GPS Library

- -

To implement a GPS driver, create a shared library that implements the interface defined in gps.h. You must name your shared library libgps.so so that it will get loaded from /system/lib at runtime. Place GPS sources and Android.mk in partner/acme/chipset_or_board/gps/ (where "acme" is your product name and "chipset_or_board" is your hardware target).

- -

The following stub Android.mk file ensures that libgps compiles and links to the appropriate libraries:

- -
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libgps
-
-LOCAL_STATIC_LIBRARIES:= \
-# include any static library dependencies
-
-LOCAL_SHARED_LIBRARIES := \
-# include any shared library dependencies
-
-LOCAL_SRC_FILES += \
-# include your source files.  eg. MyGpsLibrary.cpp
-
-LOCAL_CFLAGS += \
-# include any needed compile flags
-
-LOCAL_C_INCLUDES:= \
-# include any needed local header files
-
-include $(BUILD_SHARED_LIBRARY)
-
- - -

Interface

- - - -

- -

Note: This document relies on some Doxygen-generated content that appears in an iFrame below. To return to the Doxygen default content for this page, click here.

- - - - - -
-
- -
- -
- - - -
- - - -
v0.6 - 25 November 2008
- - - diff --git a/pdk/docs/gps.jd b/pdk/docs/gps.jd new file mode 100755 index 000000000..aa617e364 --- /dev/null +++ b/pdk/docs/gps.jd @@ -0,0 +1,49 @@ +page.title=GPS +@jd:body + + +
+Introduction
+Building a GPS Library
+Interface
+ +

Introduction

+ +

Android defines a user space C abstraction interface for GPS hardware. The interface header is defined in include/hardware/gps.h. In order to integate GPS with Android, you need to build a shared library that implements this interface.

+ + +

Building a GPS Library

+ +

To implement a GPS driver, create a shared library that implements the interface defined in gps.h. You must name your shared library libgps.so so that it will get loaded from /system/lib at runtime. Place GPS sources and Android.mk in partner/acme/chipset_or_board/gps/ (where "acme" is your product name and "chipset_or_board" is your hardware target).

+ +

The following stub Android.mk file ensures that libgps compiles and links to the appropriate libraries:

+ +
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := libgps
+
+LOCAL_STATIC_LIBRARIES:= \
+# include any static library dependencies
+
+LOCAL_SHARED_LIBRARIES := \
+# include any shared library dependencies
+
+LOCAL_SRC_FILES += \
+# include your source files.  eg. MyGpsLibrary.cpp
+
+LOCAL_CFLAGS += \
+# include any needed compile flags
+
+LOCAL_C_INCLUDES:= \
+# include any needed local header files
+
+include $(BUILD_SHARED_LIBRARY)
+
+ + +

Interface

+ + + diff --git a/pdk/docs/group__memory.html b/pdk/docs/group__memory.jd similarity index 54% rename from pdk/docs/group__memory.html rename to pdk/docs/group__memory.jd index 44d078280..87f19d5f9 100755 --- a/pdk/docs/group__memory.html +++ b/pdk/docs/group__memory.jd @@ -1,19 +1,6 @@ - - - - -Doxygen-Generated Content - - - - - +page.title=Providing Heap Memory +@jd:body + -
-

Porividng Heap Memory
+ [Neworking Support]

This is the text in the "Providing Heap Memory" subgroup
- - + diff --git a/pdk/docs/group__networking.html b/pdk/docs/group__networking.jd similarity index 57% rename from pdk/docs/group__networking.html rename to pdk/docs/group__networking.jd index 6a8e1b846..c5a94fcf2 100755 --- a/pdk/docs/group__networking.html +++ b/pdk/docs/group__networking.jd @@ -1,19 +1,6 @@ - - - - -Doxygen-Generated Content - - - - - +page.title=Networking Support +@jd:body + -
-

Neworking Support

+ +
@@ -34,5 +21,4 @@

Modules

 Porividng Heap Memory

Detailed Description

This is a text for the Networking Support Group
- - + diff --git a/pdk/docs/index.html b/pdk/docs/index.html deleted file mode 100755 index 6eac80b5a..000000000 --- a/pdk/docs/index.html +++ /dev/null @@ -1,248 +0,0 @@ - - - - -Android - Porting Guide - - - - - - - - - - - - - - - - -
- - -
- - -
-
- - - -
- -
- -
- -
- -

Android Platform Development Kit

- -
- -
- -
- -
- -
-
-
- - -

Welcome to the Android Porting Guide

- - - - -
- -

The Open Handset Distribution (OHD) is a software distribution for mobile devices, often referred to as Android, developed by members of the Open Handset Alliance.  Android includes an operating system, middleware, and key applications typically required for a mobile device.

- -

This porting guide describes the steps necessary to port Android to a new mobile device.  Android is designed as a highly-portable, hardware-independent platform based on Linux, and porting the platform to new devices requires little more than porting the Linux kernel and developing the Linux drivers necessary for your device.

- -

The current version of this guide describes bringing Android up to "PDA-level" functionality; functionality sufficient to support non-multimedia apps that run on unconnected mobile devices through the standard user interface devices such as keypad and display.  Future versions of this guide will cover complete telephony, multi-media and peripheral integration to create a complete mobile device.

- - -

Intended Audience

- -

This porting guide is intended for engineers proficient with running (and writing drivers for) Linux on embedded devices. -

The guide also assumes you have a target hardware that matches Device Requirements and that you -can boot and run a recent (2.6.x) version of the Linux kernel -with at least keypad and display drivers properly installed.

- - -

Getting Started with Android

- -

To get started with Android, start with the publicly-available documentation at http://code.google.com/android/documentation.html, paying particular attention to What is Android? and Getting Started with Android.

- - -

Porting Android to Your Device

- -

Start with the following sections in order to port Android to your target hardware.

-
-
Device Requirements
-
What must your device support in order to successfully port Android to it?
-
Setting up a Development Environment
- -
Install necessary packages and retrieve source code through a Git server. Build System offers a conceptual overview of Android's build system and instructions to affect a simple build.
-
Basic Bring up
-
Establish core components necessary to your device, such as keymaps / keyboard input and display drivers.
-
 
-
- - -

- -

-
- -
- -
- - - -
- - - -
v0.6 - 25 November 2008
- - - diff --git a/pdk/docs/index.jd b/pdk/docs/index.jd new file mode 100644 index 000000000..b7529d3a7 --- /dev/null +++ b/pdk/docs/index.jd @@ -0,0 +1,39 @@ +home=true +page.title=Welcome to the Android Porting Guide +pdk.version=1.0 +@jd:body + + +

The Open Handset Distribution (OHD) is a software distribution for mobile devices, often referred to as Android, developed by members of the Open Handset Alliance.  Android includes an operating system, middleware, and key applications typically required for a mobile device.

+ +

This porting guide describes the steps necessary to port Android to a new mobile device.  Android is designed as a highly-portable, hardware-independent platform based on Linux, and porting the platform to new devices requires little more than porting the Linux kernel and developing the Linux drivers necessary for your device.

+ +

The current version of this guide describes bringing Android up to "PDA-level" functionality; functionality sufficient to support non-multimedia apps that run on unconnected mobile devices through the standard user interface devices such as keypad and display.  Future versions of this guide will cover complete telephony, multi-media and peripheral integration to create a complete mobile device.

+ + +

Intended Audience

+ +

This porting guide is intended for engineers proficient with running (and writing drivers for) Linux on embedded devices. +

The guide also assumes you have a target hardware that matches Device Requirements and that you +can boot and run a recent (2.6.x) version of the Linux kernel +with at least keypad and display drivers properly installed.

+ + +

Getting Started with Android

+ +

To get started with Android, start with the publicly-available documentation at http://code.google.com/android/documentation.html, paying particular attention to What is Android? and Getting Started with Android.

+ + +

Porting Android to Your Device

+ +

Start with the following sections in order to port Android to your target hardware.

+
+
Device Requirements
+
What must your device support in order to successfully port Android to it?
+
Setting up a Development Environment
+ +
Install necessary packages and retrieve source code through a Git server. Build System offers a conceptual overview of Android's build system and instructions to affect a simple build.
+
Basic Bring up
+
Establish core components necessary to your device, such as keymaps / keyboard input and display drivers.
+
 
+
diff --git a/pdk/docs/instrumentation_framework.html b/pdk/docs/instrumentation_framework.jd similarity index 50% rename from pdk/docs/instrumentation_framework.html rename to pdk/docs/instrumentation_framework.jd index 306cbc6d9..a8eab2e74 100755 --- a/pdk/docs/instrumentation_framework.html +++ b/pdk/docs/instrumentation_framework.jd @@ -1,150 +1,5 @@ - - - - -Android - Instrumentation Framework - - - - - - - - - - - - - - - -
- - -
- -
-
- - - -
- -
- -
- -
-

Android Platform Development Kit

- -
- -
- -
- -
- -
-

Introduction

@@ -284,33 +139,3 @@ E/AndroidRuntime( 688): ERROR: thread attach failed

It's possible that the instrumentation apk isn't installed on your device or that the package name is incorrect in the Manifest file.

- -

- -

-
- -
- -
- - - - - - - -
v0.3 - 9 June 2008
- - - diff --git a/pdk/docs/instrumentation_testing.html b/pdk/docs/instrumentation_testing.jd similarity index 77% rename from pdk/docs/instrumentation_testing.html rename to pdk/docs/instrumentation_testing.jd index 931fd77d3..c0248aec4 100755 --- a/pdk/docs/instrumentation_testing.html +++ b/pdk/docs/instrumentation_testing.jd @@ -1,180 +1,5 @@ - - - - -Android - Porting Guide - - - - - - - - - - - - - - - - -
- - -
- - -
-
- - - -
- -
- -
- -
- -

Android Platform Development Kit

- -
- -
- -
- -
- -

Introduction

@@ -687,33 +512,3 @@ E/AndroidRuntime( 688): ERROR: thread attach failed

It's possible that the instrumentation apk isn't installed on your device or that the package name is incorrect in the Manifest file.

- -

- -

-
- -
- - - - - - - - - -
v0.6 - 25 November 2008
- - - diff --git a/pdk/docs/intro_source_code.html b/pdk/docs/intro_source_code.html deleted file mode 100755 index f86b56805..000000000 --- a/pdk/docs/intro_source_code.html +++ /dev/null @@ -1,378 +0,0 @@ - - - - -Android - Porting Guide - - - - - - - - - - - - - - - - -
- - -
- - -
-
- - - -
- -
- -
- -
- -

Android Platform Development Kit

- -
- -
- -
- -
- -
-
- - -

Introduction

- -

Android source code is maintained in two code bases: the Android Linux kernel (kernel directory) and Android platform and applications (device directory). This document provides a high-level introduction to the source code organization and an overview of the major components of each primary directory.

- -

Android Source

- - -

Linux Kernel

- -

The Android Linux kernel includes enhancements to the Linux 2.6 kernel that provide additional drivers to support the Android platform, including:

-
    -
  • Binder: an OpenBinder-based driver to facilitate inter-process communication (IPC) in the Android platform.
  • -
  • Android Power Management: a light weight power management driver built on top of standard Linux power management but optimized for embedded systems.
  • -
  • Low Memory Killer: Based on hints from the userspace, the low memory killer can kill off processes to free up memory as necessary. It is designed to provide more flexibility than the Out Of Memory (OOM) killer in the standard kernel.
  • -
  • Logger: A light weight logging device used to capture system, radio, logdata, etc.
  • -
  • USB Gadget: Uses the USB function framework.
  • -
  • Android/PMEM: The PMEM (physical memory) driver is used to provide contiguous physical memory regions to userspace libraries that interact with the digital signal processor (DSP) and other hardware that cannot cope with scatter-gather.
  • -
  • Android Alarm: A driver which provides timers that can wake the device up from sleep and a monotonic timebase that runs while the device is asleep.
  • -
-

Look for Android-specific enhancements in the following directories:

-

    -
  • /drivers/android
  • -
  • /drivers/misc
  • -
  • /include/linux
  • -
-

- - -

Android Platform and Applications

- -

The following list outlines the directory structure found within the device branch of Android source code:

- - -

- -

    - - -
  • apps -Core Android applications such as Phone, Camera, and Calendar. -
  • - - -
  • boot -Reference Android bootloader and other boot-related source code. -
  • - - -
  • commands -Common Android commands, the most important of which is the runtime command, which does much of the initialization of the system. -
  • - - -
  • config -System-wide makefiles and linker scripts. -
  • - - -
  • content -Standard Android ContentProvider modules. -
  • - - -
  • dalvik -Android runtime Virtual Machine (VM). -
  • - - -
  • data -Fonts, keymaps, sounds, timezone information, etc. -
  • - - -
  • docs -Full set of Android documentation. -
  • - - -
  • extlibs -Non-Android libraries. This directory is intended to host unmodified external code. None of the libraries included within this directory rely on Android headers or libraries. -
  • - - -
  • ide -Tools for support of the IDE's used to write Android applications. -
  • - - -
  • include -Android system headers for inclusion. -
  • - - -
  • java -Android core APIs, as well as some external libraries. -
  • - - -
  • libs -Android-specific C++ based libraries. -
  • - - -
  • partner -Project-specific source code for various proprietary components. -
  • - - -
  • prebuilt -Prebuilt tools, like the toolchains and emulator binary. -
  • - - -
  • product -Device-specific configuration files. This directory will include a subdirectory for each new device. -
  • - - -
  • samples -Sample applications. -
  • - - -
  • servers -C++ based system servers. -
  • - - -
  • system -Core of the embedded Linux platform at the heart of Android. These essential bits are required for basic booting, operation, and debugging. -
  • - - -
  • tests -Platform and application test cases. -
  • - - -
  • tools -Tools for building and debugging Android (of particular interest for porting are "adb" and "emulator"). -
  • - - - -

    - -

- - -

Adding Source Code

- -

You can develop Android applications with the same standard tools you use to develop any Java application. The Android core libraries provide the functionality needed to build rich mobile applications and the Android development tools are designed to simplify running, debugging, and testing your applications.

- -

Add project-specific source code to the Android source tree under the partner directory in a directory specific to the application or service you are building. For example, all Google-specific applications would be placed under device/partner/google/. A Google search application would be placed under device/partner/google/apps/Search. -

See Building Android for a new Mobile Device for detailed instructions.

- - - -

- -

-
- -
- -
- - - -
- - - -
v0.5 - 25 September 2008
- - - diff --git a/pdk/docs/intro_source_code.jd b/pdk/docs/intro_source_code.jd new file mode 100755 index 000000000..100f3ee5b --- /dev/null +++ b/pdk/docs/intro_source_code.jd @@ -0,0 +1,169 @@ +page.title=Source Code Overview +@jd:body + + +
+Introduction
+Android Source
+ +Linux Kernel
+Android Platform and Applications
+Adding Source Code
+ +

Introduction

+ +

Android source code is maintained in two code bases: the Android Linux kernel (kernel directory) and Android platform and applications (device directory). This document provides a high-level introduction to the source code organization and an overview of the major components of each primary directory.

+ +

Android Source

+ + +

Linux Kernel

+ +

The Android Linux kernel includes enhancements to the Linux 2.6 kernel that provide additional drivers to support the Android platform, including:

+ +

Look for Android-specific enhancements in the following directories:

+

+

+ + +

Android Platform and Applications

+ +

The following list outlines the directory structure found within the device branch of Android source code:

+ + +

+ +

+ + +

Adding Source Code

+ +

You can develop Android applications with the same standard tools you use to develop any Java application. The Android core libraries provide the functionality needed to build rich mobile applications and the Android development tools are designed to simplify running, debugging, and testing your applications.

+ +

Add project-specific source code to the Android source tree under the partner directory in a directory specific to the application or service you are building. For example, all Google-specific applications would be placed under device/partner/google/. A Google search application would be placed under device/partner/google/apps/Search. +

See Building Android for a new Mobile Device for detailed instructions.

+ + diff --git a/pdk/docs/keymaps_keyboard_input.html b/pdk/docs/keymaps_keyboard_input.jd similarity index 71% rename from pdk/docs/keymaps_keyboard_input.html rename to pdk/docs/keymaps_keyboard_input.jd index 9a1a66a42..d52a73fe3 100755 --- a/pdk/docs/keymaps_keyboard_input.html +++ b/pdk/docs/keymaps_keyboard_input.jd @@ -1,180 +1,5 @@ - - - - -Android - Porting Guide - - - - - - - - - - - - - - - - -
- - -
- - -
-
- - - -
- -
- -
- -
- -

Android Platform Development Kit

- -
- -
- -
- -
- -

Introduction

@@ -682,32 +507,3 @@ I/KeyInputQueue( 1548): Keymap: partnerxx_keypad.kl

The snippet above contains artificial line breaks to maintain a print-friendly document.

-

- -

-
- -
- - - - - - - - - -
v0.6 - 25 November 2008
- - - diff --git a/pdk/docs/power_management.html b/pdk/docs/power_management.html deleted file mode 100755 index eb510dd90..000000000 --- a/pdk/docs/power_management.html +++ /dev/null @@ -1,311 +0,0 @@ - - - - -Android - Porting Guide - - - - - - - - - - - - - - - - -
- - -
- - -
-
- - - -
- -
- -
- -
- -

Android Platform Development Kit

- -
- -
- -
- -
- -
-
- - -

Introduction

- -

Android supports its own Power Management (on top of the standard Linux Power Management) designed with the premise that the CPU shouldn't consume power if no applications or services require power. For more information regarding standard Linux power management, please see Linux Power Management Support at http://kernel.org.

-

Android requires that applications and services request CPU resources with "wake locks" through the Android application framework and native Linux libraries. If there are no active wake locks, Android will shut down the CPU.

-

The image below illustrates the Android power management architecture.

-

- -Solid elements represent Android blocks and dashed elements represent partner-specific blocks. - - - -

Wake Locks

- -

Wake locks are used by applications and services to request CPU resources.

- - -

Types of Wake Locks

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Wake Lock Description
ACQUIRE_CAUSES_WAKEUP
Normally wake locks don't actually wake the device, they just cause it to remain on once it's already on. Think of the video player app as the normal behavior. Notifications that pop up and want the device to be on are the exception; use this flag to be like them.
FULL_WAKE_LOCKWake lock that ensures that the screen and keyboard are on at full brightness.
ON_AFTER_RELEASEWhen this wake lock is released, poke the user activity timer so the screen stays on for a little longer.
PARTIAL_WAKE_LOCKWake lock that ensures that the CPU is running. The screen might not be on.
SCREEN_BRIGHT_WAKE_LOCKWake lock that ensures that the screen is on at full brightness; the keyboard backlight will be allowed to go off.
SCREEN_DIM_WAKE_LOCKWake lock that ensures that the screen is on, but the keyboard backlight will be allowed to go off, and the screen backlight will be allowed to go dim.
- - -

Exploring a Wake Lock Example

- -

All power management calls follow the same basic format:

-

  1. Acquire handle to the PowerManager service.
  2. -
  3. Create a wake lock and specify the power management flags for screen, timeout, etc.
  4. -
  5. Acquire wake lock.
  6. -
  7. Perform operation (play MP3, open HTML page, etc.).
  8. -
  9. Release wake lock.
  10. -
-

-

The snippet below illustrates this process.

-
-PowerManager pm = (PowerManager)mContext.getSystemService(
-                                          Context.POWER_SERVICE);
-PowerManager.WakeLock wl = pm.newWakeLock(
-                                      PowerManager.SCREEN_DIM_WAKE_LOCK
-                                      | PowerManager.ON_AFTER_RELEASE,
-                                      TAG);
-wl.acquire();
- // ...
-wl.release();
-
- - -

PowerManager class

- -

The Android Framework exposes power management to services and applications through the PowerManager class.

-

User space native libraries (any hardware function in //device/lib/hardware/ meant to serve as supporting libraries for Android runtime) should never call into Android Power Management directly (see the image above). Bypassing the power management policy in the Android runtime will destabilize the system.

-

All calls into Power Management should go through the Android runtime PowerManager APIs.

-

Please visit -http://code.google.com/android/reference/android/os/PowerManager.html for a description of the API and examples.

- - -

Registering Drivers with the PM Driver

- -

You can register Kernel-level drivers with the Android Power Manager driver so that they're notified immediately before power down or after power up. For example, you might set a display driver to completely power down when a request comes in to power down from the user space (see the Android MSM MDDI display driver for a sample implementation).

-

To register drivers with the Android PM driver, implement call-back handlers and register them with the Android PM, as illustrated in the snippet below:

-
-android_register_early_suspend(android_early_suspend_t *handler)
-android_register_early_resume(android_early_resume_t *handler)
-
-

It is critical in a drive to return immediately and not wait for anything to happen in the call back.

- - -

- -

-
- -
- -
- - - -
- - - -
v0.6 - 25 November 2008
- - - diff --git a/pdk/docs/power_management.jd b/pdk/docs/power_management.jd new file mode 100755 index 000000000..52c23e803 --- /dev/null +++ b/pdk/docs/power_management.jd @@ -0,0 +1,108 @@ +page.title=Power Management +@jd:body + + +
+Introduction
+Wake Locks
+ +Types of Wake Locks
+Exploring a Wake Lock Example
+PowerManager class
+Registering Drivers with the PM Driver
+ +

Introduction

+ +

Android supports its own Power Management (on top of the standard Linux Power Management) designed with the premise that the CPU shouldn't consume power if no applications or services require power. For more information regarding standard Linux power management, please see Linux Power Management Support at http://kernel.org.

+

Android requires that applications and services request CPU resources with "wake locks" through the Android application framework and native Linux libraries. If there are no active wake locks, Android will shut down the CPU.

+

The image below illustrates the Android power management architecture.

+

+ +

Solid elements represent Android blocks and dashed elements represent partner-specific blocks.

+ + + +

Wake Locks

+ +

Wake locks are used by applications and services to request CPU resources.

+ + +

Types of Wake Locks

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Wake Lock Description
ACQUIRE_CAUSES_WAKEUP
Normally wake locks don't actually wake the device, they just cause it to remain on once it's already on. Think of the video player app as the normal behavior. Notifications that pop up and want the device to be on are the exception; use this flag to be like them.
FULL_WAKE_LOCKWake lock that ensures that the screen and keyboard are on at full brightness.
ON_AFTER_RELEASEWhen this wake lock is released, poke the user activity timer so the screen stays on for a little longer.
PARTIAL_WAKE_LOCKWake lock that ensures that the CPU is running. The screen might not be on.
SCREEN_BRIGHT_WAKE_LOCKWake lock that ensures that the screen is on at full brightness; the keyboard backlight will be allowed to go off.
SCREEN_DIM_WAKE_LOCKWake lock that ensures that the screen is on, but the keyboard backlight will be allowed to go off, and the screen backlight will be allowed to go dim.
+ + +

Exploring a Wake Lock Example

+ +

All power management calls follow the same basic format:

+

  1. Acquire handle to the PowerManager service.
  2. +
  3. Create a wake lock and specify the power management flags for screen, timeout, etc.
  4. +
  5. Acquire wake lock.
  6. +
  7. Perform operation (play MP3, open HTML page, etc.).
  8. +
  9. Release wake lock.
  10. +
+

+

The snippet below illustrates this process.

+
+PowerManager pm = (PowerManager)mContext.getSystemService(
+                                          Context.POWER_SERVICE);
+PowerManager.WakeLock wl = pm.newWakeLock(
+                                      PowerManager.SCREEN_DIM_WAKE_LOCK
+                                      | PowerManager.ON_AFTER_RELEASE,
+                                      TAG);
+wl.acquire();
+ // ...
+wl.release();
+
+ + +

PowerManager class

+ +

The Android Framework exposes power management to services and applications through the PowerManager class.

+

User space native libraries (any hardware function in //device/lib/hardware/ meant to serve as supporting libraries for Android runtime) should never call into Android Power Management directly (see the image above). Bypassing the power management policy in the Android runtime will destabilize the system.

+

All calls into Power Management should go through the Android runtime PowerManager APIs.

+

Please visit +http://code.google.com/android/reference/android/os/PowerManager.html for a description of the API and examples.

+ + +

Registering Drivers with the PM Driver

+ +

You can register Kernel-level drivers with the Android Power Manager driver so that they're notified immediately before power down or after power up. For example, you might set a display driver to completely power down when a request comes in to power down from the user space (see the Android MSM MDDI display driver for a sample implementation).

+

To register drivers with the Android PM driver, implement call-back handlers and register them with the Android PM, as illustrated in the snippet below:

+
+android_register_early_suspend(android_early_suspend_t *handler)
+android_register_early_resume(android_early_resume_t *handler)
+
+

It is critical in a drive to return immediately and not wait for anything to happen in the call back.

+ + + diff --git a/pdk/docs/source_setup_guide.html b/pdk/docs/source_setup_guide.html deleted file mode 100755 index 1588b2946..000000000 --- a/pdk/docs/source_setup_guide.html +++ /dev/null @@ -1,323 +0,0 @@ - - - - -Android - Porting Guide - - - - - - - - - - - - - - - - -
- - -
- - -
-
- - - -
- -
- -
- -
- -

Android Platform Development Kit

- -
- -
- -
- -
- -
-
- - -

Introduction

- -

This section provides instructions on how to configure your host system to build Android for mobile devices. While Android is designed as host-environment agnostic, it has been tested and is known to work on the following Linux operating system; Ubuntu 6.06 (Dapper), 7.10 (Gutsy), and 8.04. Cygwin is not recommended.

- - -

Installing Packages

- - - -

Required Packages

- -

Android requires the following system packages:

-

    -
  • flex: This lexical analyzer generator is used to read a given input file for a description of a scanner to generate.
  • -
  • bison: This is a general-purpose parser generator.
  • -
  • gperf: This is a perfect hash function generator.
  • -
  • libesd0-dev: This enlightened sound daemon (dev files) is used to mix digitized audio streams for playback by a single device.
  • -
  • libwxgtk2.6-dev: This package provides GUI components and other facilities for many different platforms.
  • -
  • build-essential: This package contains a list of packages considered fundamental to building Debian packages.
  • -

- - -

Ubuntu 6.06 (Dapper)

- -

On a clean Dapper system, type the following:

-
-% sudo apt-get install flex bison gperf libesd0-dev libwxgtk2.6-dev zlib1g-dev 
-   build-essential
-
-

This snippet includes an artificial line break to maintain a print-friendly document.

- - -

Ubuntu 7.10

- -
  1. The libwxgtk2.6-dev package will only work if the following code is included in your /etc/apt/source file. -

    -## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu
    -## team, and may not be under a free license. Please satisfy yourself as to
    -## your rights to use the software. Also, please note that software in
    -## universe WILL NOT receive any review or updates from the Ubuntu security
    -## team.
    -# Line commented out by installer because it failed to verify:
    -deb http://us.archive.ubuntu.com/ubuntu/ gutsy universe
    -# Line commented out by installer because it failed to verify:
    -deb-src http://us.archive.ubuntu.com/ubuntu/ gutsy universe
    -# Line commented out by installer because it failed to verify:
    -deb http://us.archive.ubuntu.com/ubuntu/ gutsy-updates universe
    -# Line commented out by installer because it failed to verify:
    -deb-src http://us.archive.ubuntu.com/ubuntu/ gutsy-updates universe
    -

  2. -
  3. Install required packages with the following command: -

    -% sudo apt-get install flex bison gperf libesd0-dev libwxgtk2.6-dev zlib1g-dev
    -   build-essential
    -

    -This snippet includes an artificial line break to maintain a print-friendly document. -
  4. -
  5. -

    Install the X11 development environment with the following commands:

    -

    -% sudo apt-get install x-dev
    -% sudo apt-get install libx11-dev
    -% sudo apt-get install libncurses5-dev
    -

    -
  6. -
- - -

Ubuntu 8.04

- -

On a clean system, type the following:

-
-% sudo apt-get install flex bison gperf libesd0-dev libwxgtk2.6-dev
-zlib1g-dev build-essential
-% sudo apt-get install x-dev
-% sudo apt-get install libx11-dev
-% sudo apt-get install libncurses5-dev
-% sudo apt-get install sun-java5-jdk
-
- - -

Installing Java

- -

Android source code includes a hard dependency on the Java Developer Kit (JDK) 5.0 Update 12 or greater. The specific file name of the Update 12 package is jdk-1_5_0_12-linux-i586.bin. To download this version of the Java JDK:

-

    -
  1. Navigate to: http://java.sun.com/products/archive/.
  2. -
  3. Select '5.0 Update 12' from the 'Java 2 Platform Standard Edition (J2SE)' -> 'JDK/JRE - 5.0' field and click 'Go.'
  4. -
  5. Click 'Download JDK.'
  6. -
  7. In the 'Linux Platform' section, click 'Linux self-extracting file' associated with the jdk-1_5_0_12-linux-i586.bin package.
  8. -
  9. Follow the installation instructions.
  10. -
-

- -

Once you have cleanly installed the JDK, modify your PATH environment variable to include <jdk-install-dir>/jdk1.5.0_12/bin at its beginning so that Dapper will use the correct installation.

-

Ubuntu 7.10

-

An alternative method to quickly install Java is to enable multiverse repo in /etc/apt/sources.list and then execute:

-
-% sudo apt-get install sun-java5-jdk
-
- - -

- -

-
- -
- -
- - - -
- - - -
v0.5 - 25 September 2008
- - - diff --git a/pdk/docs/source_setup_guide.jd b/pdk/docs/source_setup_guide.jd new file mode 100755 index 000000000..5c0bed5e1 --- /dev/null +++ b/pdk/docs/source_setup_guide.jd @@ -0,0 +1,116 @@ +page.title=Host System Setup +@jd:body + + +
+Introduction
+Installing Packages
+ +Required Packages
+Ubuntu 6.06 (Dapper)
+Ubuntu 7.10
+Ubuntu 8.04
+Installing Java
+ +

Introduction

+ +

This section provides instructions on how to configure your host system to build Android for mobile devices. While Android is designed as host-environment agnostic, it has been tested and is known to work on the following Linux operating system; Ubuntu 6.06 (Dapper), 7.10 (Gutsy), and 8.04. Cygwin is not recommended.

+ + +

Installing Packages

+ + + +

Required Packages

+ +

Android requires the following system packages:

+

+ + +

Ubuntu 6.06 (Dapper)

+ +

On a clean Dapper system, type the following:

+
+% sudo apt-get install flex bison gperf libesd0-dev libwxgtk2.6-dev zlib1g-dev 
+   build-essential
+
+

This snippet includes an artificial line break to maintain a print-friendly document.

+ + +

Ubuntu 7.10

+ +
  1. The libwxgtk2.6-dev package will only work if the following code is included in your /etc/apt/source file. +

    +## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu
    +## team, and may not be under a free license. Please satisfy yourself as to
    +## your rights to use the software. Also, please note that software in
    +## universe WILL NOT receive any review or updates from the Ubuntu security
    +## team.
    +# Line commented out by installer because it failed to verify:
    +deb http://us.archive.ubuntu.com/ubuntu/ gutsy universe
    +# Line commented out by installer because it failed to verify:
    +deb-src http://us.archive.ubuntu.com/ubuntu/ gutsy universe
    +# Line commented out by installer because it failed to verify:
    +deb http://us.archive.ubuntu.com/ubuntu/ gutsy-updates universe
    +# Line commented out by installer because it failed to verify:
    +deb-src http://us.archive.ubuntu.com/ubuntu/ gutsy-updates universe
    +

  2. +
  3. Install required packages with the following command: +

    +% sudo apt-get install flex bison gperf libesd0-dev libwxgtk2.6-dev zlib1g-dev
    +   build-essential
    +

    +This snippet includes an artificial line break to maintain a print-friendly document. +
  4. +
  5. +

    Install the X11 development environment with the following commands:

    +

    +% sudo apt-get install x-dev
    +% sudo apt-get install libx11-dev
    +% sudo apt-get install libncurses5-dev
    +

    +
  6. +
+ + +

Ubuntu 8.04

+ +

On a clean system, type the following:

+
+% sudo apt-get install flex bison gperf libesd0-dev libwxgtk2.6-dev
+zlib1g-dev build-essential
+% sudo apt-get install x-dev
+% sudo apt-get install libx11-dev
+% sudo apt-get install libncurses5-dev
+% sudo apt-get install sun-java5-jdk
+
+ + +

Installing Java

+ +

Android source code includes a hard dependency on the Java Developer Kit (JDK) 5.0 Update 12 or greater. The specific file name of the Update 12 package is jdk-1_5_0_12-linux-i586.bin. To download this version of the Java JDK:

+

    +
  1. Navigate to: http://java.sun.com/products/archive/.
  2. +
  3. Select '5.0 Update 12' from the 'Java 2 Platform Standard Edition (J2SE)' -> 'JDK/JRE - 5.0' field and click 'Go.'
  4. +
  5. Click 'Download JDK.'
  6. +
  7. In the 'Linux Platform' section, click 'Linux self-extracting file' associated with the jdk-1_5_0_12-linux-i586.bin package.
  8. +
  9. Follow the installation instructions.
  10. +
+

+ +

Once you have cleanly installed the JDK, modify your PATH environment variable to include <jdk-install-dir>/jdk1.5.0_12/bin at its beginning so that Dapper will use the correct installation.

+

Ubuntu 7.10

+

An alternative method to quickly install Java is to enable multiverse repo in /etc/apt/sources.list and then execute:

+
+% sudo apt-get install sun-java5-jdk
+
+ + + diff --git a/pdk/docs/system_requirements.html b/pdk/docs/system_requirements.html deleted file mode 100755 index 2f236cf80..000000000 --- a/pdk/docs/system_requirements.html +++ /dev/null @@ -1,262 +0,0 @@ - - - - -Android - Porting Guide - - - - - - - - - - - - - - - - -
- - -
- - -
-
- - - -
- -
- -
- -
- -

Android Platform Development Kit

- -
- -
- -
- -
- -
-
-
- - -

Device Requirements

- -

While Android is designed to support a wide variety of hardware platforms and configurations, this section provides recommended minimum device requirements.

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FeatureMinimum RequirementNotes
ChipsetARM-basedFor the first release, Android is primarily targeted towards mobile handsets and portions of the platform, such as Dalvik VM graphics processing, currently assume an ARM architecture.
Memory128 MB RAM; 256 MB Flash ExternalAndroid can boot and run in configurations with less memory, but it isn't recommended.
StorageMini or Micro SD Not necessary for basic bring up, but recommended.
Primary Display HVGA requiredThe current Android interface targets a touch-based HVGA resolution display with a touch-interface no smaller than 2.8 inches in size. However, smaller displays will suffice for initial porting.
Navigation Keys 5-way navigation with 5 application keys, power, camera and volume controls 
Camera2MP CMOSNot required for basic bring up.
USBStandard mini-B USB interfaceAndroid uses the USB interface for flashing the device system images and debugging a running device.
Bluetooth1.2 or 2.0 Not required for initial bring up.
-

If available, your Android device can also benefit from the following optional device characteristics:

-
    -
  • QWERTY keyboard
  • -
  • WiFi
  • -
  • GPS
  • -
- - -

- -

-
- -
- -
- - - -
- - - -
v0.6 - 25 November 2008
-
- - diff --git a/pdk/docs/system_requirements.jd b/pdk/docs/system_requirements.jd new file mode 100755 index 000000000..1b203ea2f --- /dev/null +++ b/pdk/docs/system_requirements.jd @@ -0,0 +1,63 @@ +page.title=Device Requirements +pdk.version=1.0 +@jd:body + +

While Android is designed to support a wide variety of hardware platforms and configurations, this section provides recommended minimum device requirements.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
FeatureMinimum RequirementNotes
ChipsetARM-basedFor the first release, Android is primarily targeted towards mobile handsets and portions of the platform, such as Dalvik VM graphics processing, currently assume an ARM architecture.
Memory128 MB RAM; 256 MB Flash ExternalAndroid can boot and run in configurations with less memory, but it isn't recommended.
StorageMini or Micro SD Not necessary for basic bring up, but recommended.
Primary Display HVGA requiredThe current Android interface targets a touch-based HVGA resolution display with a touch-interface no smaller than 2.8 inches in size. However, smaller displays will suffice for initial porting.
Navigation Keys 5-way navigation with 5 application keys, power, camera and volume controls 
Camera2MP CMOSNot required for basic bring up.
USBStandard mini-B USB interfaceAndroid uses the USB interface for flashing the device system images and debugging a running device.
Bluetooth1.2 or 2.0 Not required for initial bring up.
+

If available, your Android device can also benefit from the following optional device characteristics:

+ + + + diff --git a/pdk/docs/telephony.html b/pdk/docs/telephony.jd similarity index 61% rename from pdk/docs/telephony.html rename to pdk/docs/telephony.jd index d4826f693..99a12c0e9 100755 --- a/pdk/docs/telephony.html +++ b/pdk/docs/telephony.jd @@ -1,180 +1,5 @@ - - - - -Android - Porting Guide - - - - - - - - - - - - - - - - -
- - -
- - -
-
- - - -
- -
- -
- -
- -

Android Platform Development Kit

- -
- -
- -
- -
- -
-

Introduction

@@ -397,33 +222,3 @@ RIL_RadioFunctions;

- -

- -

-
- -
- - - - - - - - - -
v0.6 - 25 November 2008
- - - diff --git a/pdk/docs/wifi.html b/pdk/docs/wifi.html deleted file mode 100755 index df40fb0a0..000000000 --- a/pdk/docs/wifi.html +++ /dev/null @@ -1,250 +0,0 @@ - - - - -Android - Porting Guide - - - - - - - - - - - - - - - - -
- - -
- - -
-
- - - -
- -
- -
- -
- -

Android Platform Development Kit

- -
- -
- -
- -
- -
-
- - -

Introduction

- -

Android uses wpa_supplicant as the platform interface to the Wi-Fi device. Your Wi-Fi driver must be compatible with the standard wpa_supplicant in addition to extensions added to the supplicant (specifically, the "DRIVER" commands described in wifi.h/wifi_command()).

- - -

Building a Wi-Fi Library

- -

To create a Wi-Fi driver for Android:

-

    -
  • create a shared library that implements the interface defined in include/hardware/wifi.h, which also defines the Wi-Fi supplicant.
  • -
  • Follow the instructions posted at http://hostap.epitest.fi/wpa_supplicant/.
  • -
  • Place your driver in libs/hardware/wifi/
  • -
  • Test your driver using the command line wpa_cli utilities.
  • -
- -

You can find the default implementation in libs/hardware/wifi/wifi.c. If you need to make changes, create a new source file similar to wifi.c, for example, wifi_mywifi.c.

- -

Update the default Android.mk file (libs/hardware/wifi/Android.mk) as shown below.

-
-LOCAL_SHARED_LIBRARIES += libnetutils
-
-ifeq ($(TARGET_DEVICE),acme)
-LOCAL_SRC_FILES += wifi/wifi_mywifi.c
-else
-LOCAL_SRC_FILES += wifi/wifi.c
-endif
-
- - -

Interface

- - - -

Note: This document relies on some Doxygen-generated content that appears in an iFrame below. To return to the Doxygen default content for this page, click here.

- - - - - -
-
- -
- -
- - - -
- - - -
v0.6 - 25 November 2008
- - - diff --git a/pdk/docs/wifi.jd b/pdk/docs/wifi.jd new file mode 100755 index 000000000..42cb14cad --- /dev/null +++ b/pdk/docs/wifi.jd @@ -0,0 +1,49 @@ +page.title=Wi-Fi +@jd:body + + +
+Introduction
+Building a Wi-Fi Library
+Interface
+ +

Introduction

+ +

Android uses wpa_supplicant as the platform interface to the Wi-Fi device. Your Wi-Fi driver must be compatible with the standard wpa_supplicant in addition to extensions added to the supplicant (specifically, the "DRIVER" commands described in wifi.h/wifi_command()).

+ + +

Building a Wi-Fi Library

+ +

To create a Wi-Fi driver for Android:

+

+ +

You can find the default implementation in libs/hardware/wifi/wifi.c. If you need to make changes, create a new source file similar to wifi.c, for example, wifi_mywifi.c.

+ +

Update the default Android.mk file (libs/hardware/wifi/Android.mk) as shown below.

+
+LOCAL_SHARED_LIBRARIES += libnetutils
+
+ifeq ($(TARGET_DEVICE),acme)
+LOCAL_SRC_FILES += wifi/wifi_mywifi.c
+else
+LOCAL_SRC_FILES += wifi/wifi.c
+endif
+
+ + +

Interface

+ + + +

Note: This document relies on some Doxygen-generated content that appears in an iFrame below. To return to the Doxygen default content for this page, click here.

+ + + + + + diff --git a/pdk/hosting/app.yaml b/pdk/hosting/app.yaml index 407cbb08b..6e08141bc 100644 --- a/pdk/hosting/app.yaml +++ b/pdk/hosting/app.yaml @@ -4,8 +4,8 @@ runtime: python api_version: 1 handlers: -- url: /docs - static_dir: docs +- url: /online-pdk + static_dir: online-pdk - url: / script: pdk.py diff --git a/pdk/hosting/pdk.py b/pdk/hosting/pdk.py index e88f826f8..421f19550 100644 --- a/pdk/hosting/pdk.py +++ b/pdk/hosting/pdk.py @@ -26,11 +26,9 @@ from google.appengine.ext.webapp.util import run_wsgi_app class MainPage(webapp.RequestHandler): def get(self): - self.redirect('docs/index.html') + self.redirect('online-pdk/index.html') -application = webapp.WSGIApplication( - [('/', MainPage)], - debug=True) +application = webapp.WSGIApplication([('/', MainPage)], debug=True) def main(): run_wsgi_app(application) @@ -38,6 +36,18 @@ def main(): if __name__ == "__main__": main() +# Testing +# You must install google appengine. See: http://code.google.com/appengine/downloads.html +# +# Here's the command to run the pdk-docs server locally: +# python /dev_appserver.py --address 0.0.0.0 \ +# /android/out/target/common/docs + +# To verify it is working you can access it with a browser loacally on port 8080: + +# http://localhost:8080/index.html + + # To upload this application: # /home/build/static/projects/apphosting/devtools/appcfg.py update pdk/ # where the pdk directory contains: pdk.py, app.yaml, and the docs directory. From a248b46de49f344d91098f2f3c189ec60151728c Mon Sep 17 00:00:00 2001 From: Xavier Ducrohet <> Date: Thu, 2 Apr 2009 11:32:07 -0700 Subject: [PATCH 20/45] AI 144252: Reload AVDs when displaying the run/debug launch dialog (bug #1683892) BUG=1683892 Automated import of CL 144252 --- .../ide/eclipse/adt/launch/EmulatorConfigTab.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/EmulatorConfigTab.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/EmulatorConfigTab.java index 3789153e4..24380eb62 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/EmulatorConfigTab.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/launch/EmulatorConfigTab.java @@ -21,6 +21,7 @@ import com.android.ide.eclipse.adt.launch.AndroidLaunchConfiguration.TargetMode; import com.android.ide.eclipse.adt.sdk.Sdk; import com.android.ide.eclipse.common.project.BaseProjectHelper; import com.android.ide.eclipse.ddms.DdmsPlugin; +import com.android.prefs.AndroidLocation.AndroidLocationException; import com.android.sdklib.IAndroidTarget; import com.android.sdklib.avd.AvdManager; import com.android.sdklib.avd.AvdManager.AvdInfo; @@ -126,6 +127,14 @@ public class EmulatorConfigTab extends AbstractLaunchConfigurationTab { */ public void createControl(Composite parent) { Font font = parent.getFont(); + + // reload the AVDs to make sure we are up to date + try { + Sdk.getCurrent().getAvdManager().reloadAvds(); + } catch (AndroidLocationException e1) { + // this happens if the AVD Manager failed to find the folder in which the AVDs are + // stored. There isn't much we can do at this point. + } Composite topComp = new Composite(parent, SWT.NONE); setControl(topComp); From ad41d46aa3c26b0ccca6e2c2caa2a2388f8db6a0 Mon Sep 17 00:00:00 2001 From: Brett Chabot <> Date: Thu, 2 Apr 2009 11:50:35 -0700 Subject: [PATCH 21/45] AI 144260: Add constant for test file name in runtest. Automated import of CL 144260 --- testrunner/runtest.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/testrunner/runtest.py b/testrunner/runtest.py index 8d3659130..243da77b5 100755 --- a/testrunner/runtest.py +++ b/testrunner/runtest.py @@ -39,14 +39,17 @@ import test_defs class TestRunner(object): """Command line utility class for running pre-defined Android test(s).""" + _TEST_FILE_NAME = "test_defs.xml" + # file path to android core platform tests, relative to android build root # TODO move these test data files to another directory - _CORE_TEST_PATH = os.path.join("development", "testrunner", "test_defs.xml") + _CORE_TEST_PATH = os.path.join("development", "testrunner", + _TEST_FILE_NAME) # vendor glob file path patterns to tests, relative to android # build root _VENDOR_TEST_PATH = os.path.join("vendor", "*", "tests", "testinfo", - "test_defs.xml") + _TEST_FILE_NAME) _RUNTEST_USAGE = ( "usage: runtest.py [options] short-test-name[s]\n\n" @@ -61,7 +64,7 @@ class TestRunner(object): """Processes command-line options.""" # TODO error messages on once-only or mutually-exclusive options. user_test_default = os.path.join(os.environ.get("HOME"), ".android", - "test_defs.xml") + self._TEST_FILE_NAME) parser = optparse.OptionParser(usage=self._RUNTEST_USAGE) From b41d8daf77eabd6c4c9b818056f69bee603466fe Mon Sep 17 00:00:00 2001 From: Raphael Moll <> Date: Thu, 2 Apr 2009 13:42:29 -0700 Subject: [PATCH 22/45] AI 144283: ADT: Enhance Resource Chooser with ability to create new XML strings. That's a first pass. There's a fair bit of refactoring involved, so it's split in two CLs. Next CL will add more functionality. BUG=1722971 Automated import of CL 144283 --- .../extractstring/ExtractStringInputPage.java | 393 ++-------------- .../ExtractStringRefactoring.java | 210 ++++----- .../extractstring/ExtractStringWizard.java | 2 +- .../adt/ui/ReferenceChooserDialog.java | 95 +++- .../wizards/newstring/NewStringBaseImpl.java | 439 ++++++++++++++++++ .../wizards/newstring/NewStringHelper.java | 122 +++++ .../wizards/newstring/NewStringWizard.java | 66 +++ .../newstring/NewStringWizardPage.java | 127 +++++ .../uimodel/UiResourceAttributeNode.java | 4 +- 9 files changed, 985 insertions(+), 473 deletions(-) create mode 100644 tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newstring/NewStringBaseImpl.java create mode 100644 tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newstring/NewStringHelper.java create mode 100644 tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newstring/NewStringWizard.java create mode 100644 tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newstring/NewStringWizardPage.java diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/refactorings/extractstring/ExtractStringInputPage.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/refactorings/extractstring/ExtractStringInputPage.java index 9822b32e7..1f50c07b6 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/refactorings/extractstring/ExtractStringInputPage.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/refactorings/extractstring/ExtractStringInputPage.java @@ -17,72 +17,34 @@ package com.android.ide.eclipse.adt.refactorings.extractstring; -import com.android.ide.eclipse.adt.ui.ConfigurationSelector; -import com.android.ide.eclipse.common.AndroidConstants; -import com.android.ide.eclipse.editors.resources.configurations.FolderConfiguration; -import com.android.ide.eclipse.editors.resources.manager.ResourceFolderType; -import com.android.sdklib.SdkConstants; +import com.android.ide.eclipse.adt.wizards.newstring.NewStringBaseImpl; +import com.android.ide.eclipse.adt.wizards.newstring.NewStringBaseImpl.INewStringPageCallback; +import com.android.ide.eclipse.adt.wizards.newstring.NewStringBaseImpl.ValidationStatus; -import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; -import org.eclipse.core.resources.IResource; -import org.eclipse.core.runtime.CoreException; import org.eclipse.jface.wizard.IWizardPage; -import org.eclipse.jface.wizard.WizardPage; import org.eclipse.ltk.ui.refactoring.UserInputWizardPage; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; -import org.eclipse.swt.widgets.Combo; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; -import java.util.HashMap; -import java.util.TreeSet; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - /** * @see ExtractStringRefactoring */ -class ExtractStringInputPage extends UserInputWizardPage implements IWizardPage { +class ExtractStringInputPage extends UserInputWizardPage + implements IWizardPage, INewStringPageCallback { - /** Last res file path used, shared across the session instances but specific to the - * current project. The default for unknown projects is {@link #DEFAULT_RES_FILE_PATH}. */ - private static HashMap sLastResFilePath = new HashMap(); - - /** The project where the user selection happened. */ - private final IProject mProject; - - /** Field displaying the user-selected string to be replaced. */ - private Label mStringLabel; - /** Test field where the user enters the new ID to be generated or replaced with. */ - private Text mNewIdTextField; - /** The configuration selector, to select the resource path of the XML file. */ - private ConfigurationSelector mConfigSelector; - /** The combo to display the existing XML files or enter a new one. */ - private Combo mResFileCombo; - - /** Regex pattern to read a valid res XML file path. It checks that the are 2 folders and - * a leaf file name ending with .xml */ - private static final Pattern RES_XML_FILE_REGEX = Pattern.compile( - "/res/[a-z][a-zA-Z0-9_-]+/[^.]+\\.xml"); //$NON-NLS-1$ - /** Absolute destination folder root, e.g. "/res/" */ - private static final String RES_FOLDER_ABS = - AndroidConstants.WS_RESOURCES + AndroidConstants.WS_SEP; - /** Relative destination folder root, e.g. "res/" */ - private static final String RES_FOLDER_REL = - SdkConstants.FD_RESOURCES + AndroidConstants.WS_SEP; - - private static final String DEFAULT_RES_FILE_PATH = "/res/values/strings.xml"; + private NewStringBaseImpl mImpl; public ExtractStringInputPage(IProject project) { super("ExtractStringInputPage"); //$NON-NLS-1$ - mProject = project; + mImpl = new NewStringBaseImpl(project, this); } /** @@ -92,17 +54,12 @@ class ExtractStringInputPage extends UserInputWizardPage implements IWizardPage * {@link ExtractStringRefactoring}. */ public void createControl(Composite parent) { - Composite content = new Composite(parent, SWT.NONE); - GridLayout layout = new GridLayout(); layout.numColumns = 1; content.setLayout(layout); - - createStringReplacementGroup(content); - createResFileGroup(content); - validatePage(); + mImpl.createControl(content); setControl(content); } @@ -111,8 +68,9 @@ class ExtractStringInputPage extends UserInputWizardPage implements IWizardPage * and by which options. * * @param content A composite with a 1-column grid layout + * @return The {@link Text} field for the new String ID name. */ - private void createStringReplacementGroup(Composite content) { + public Text createStringGroup(Composite content) { final ExtractStringRefactoring ref = getOurRefactoring(); @@ -124,16 +82,27 @@ class ExtractStringInputPage extends UserInputWizardPage implements IWizardPage layout.numColumns = 2; group.setLayout(layout); - // line: String found in selection + // line: Textfield for string value (based on selection, if any) Label label = new Label(group, SWT.NONE); label.setText("String:"); String selectedString = ref.getTokenString(); - mStringLabel = new Label(group, SWT.NONE); - mStringLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mStringLabel.setText(selectedString != null ? selectedString : ""); + final Text stringValueField = new Text(group, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + stringValueField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + stringValueField.setText(selectedString != null ? selectedString : ""); //$NON-NLS-1$ + + ref.setNewStringValue(stringValueField.getText()); + + stringValueField.addModifyListener(new ModifyListener() { + public void modifyText(ModifyEvent e) { + if (mImpl.validatePage()) { + ref.setNewStringValue(stringValueField.getText()); + } + } + }); + // TODO provide an option to replace all occurences of this string instead of // just the one. @@ -143,74 +112,31 @@ class ExtractStringInputPage extends UserInputWizardPage implements IWizardPage label = new Label(group, SWT.NONE); label.setText("Replace by R.string."); - mNewIdTextField = new Text(group, SWT.SINGLE | SWT.LEFT | SWT.BORDER); - mNewIdTextField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mNewIdTextField.setText(guessId(selectedString)); + final Text stringIdField = new Text(group, SWT.SINGLE | SWT.LEFT | SWT.BORDER); + stringIdField.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + stringIdField.setText(guessId(selectedString)); - ref.setReplacementStringId(mNewIdTextField.getText().trim()); + ref.setNewStringId(stringIdField.getText().trim()); - mNewIdTextField.addModifyListener(new ModifyListener() { + stringIdField.addModifyListener(new ModifyListener() { public void modifyText(ModifyEvent e) { - if (validatePage()) { - ref.setReplacementStringId(mNewIdTextField.getText().trim()); + if (mImpl.validatePage()) { + ref.setNewStringId(stringIdField.getText().trim()); } } }); - } - - /** - * Creates the lower group with the fields to choose the resource confirmation and - * the target XML file. - * - * @param content A composite with a 1-column grid layout - */ - private void createResFileGroup(Composite content) { - - Group group = new Group(content, SWT.NONE); - group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - group.setText("XML resource to edit"); - - GridLayout layout = new GridLayout(); - layout.numColumns = 2; - group.setLayout(layout); - // line: selection of the res config - - Label label; - label = new Label(group, SWT.NONE); - label.setText("Configuration:"); - - mConfigSelector = new ConfigurationSelector(group); - GridData gd = new GridData(2, GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL); - gd.widthHint = ConfigurationSelector.WIDTH_HINT; - gd.heightHint = ConfigurationSelector.HEIGHT_HINT; - mConfigSelector.setLayoutData(gd); - OnConfigSelectorUpdated onConfigSelectorUpdated = new OnConfigSelectorUpdated(); - mConfigSelector.setOnChangeListener(onConfigSelectorUpdated); - - // line: selection of the output file - - label = new Label(group, SWT.NONE); - label.setText("Resource file:"); - - mResFileCombo = new Combo(group, SWT.DROP_DOWN); - mResFileCombo.select(0); - mResFileCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); - mResFileCombo.addModifyListener(onConfigSelectorUpdated); - - // set output file name to the last one used - - String projPath = mProject.getFullPath().toPortableString(); - String filePath = sLastResFilePath.get(projPath); - - mResFileCombo.setText(filePath != null ? filePath : DEFAULT_RES_FILE_PATH); - onConfigSelectorUpdated.run(); + return stringIdField; } /** * Utility method to guess a suitable new XML ID based on the selected string. */ private String guessId(String text) { + if (text == null) { + return ""; //$NON-NLS-1$ + } + // make lower case text = text.toLowerCase(); @@ -231,247 +157,8 @@ class ExtractStringInputPage extends UserInputWizardPage implements IWizardPage return (ExtractStringRefactoring) getRefactoring(); } - /** - * Validates fields of the wizard input page. Displays errors as appropriate and - * enable the "Next" button (or not) by calling {@link #setPageComplete(boolean)}. - * - * @return True if the page has been positively validated. It may still have warnings. - */ - private boolean validatePage() { - boolean success = true; - - // Analyze fatal errors. - - String text = mNewIdTextField.getText().trim(); - if (text == null || text.length() < 1) { - setErrorMessage("Please provide a resource ID to replace with."); - success = false; - } else { - for (int i = 0; i < text.length(); i++) { - char c = text.charAt(i); - boolean ok = i == 0 ? - Character.isJavaIdentifierStart(c) : - Character.isJavaIdentifierPart(c); - if (!ok) { - setErrorMessage(String.format( - "The resource ID must be a valid Java identifier. The character %1$c at position %2$d is not acceptable.", - c, i+1)); - success = false; - break; - } - } - } - - String resFile = mResFileCombo.getText(); - if (success) { - if (resFile == null || resFile.length() == 0) { - setErrorMessage("A resource file name is required."); - success = false; - } else if (!RES_XML_FILE_REGEX.matcher(resFile).matches()) { - setErrorMessage("The XML file name is not valid."); - success = false; - } - } - - // Analyze info & warnings. - - if (success) { - setErrorMessage(null); - - ExtractStringRefactoring ref = getOurRefactoring(); - - ref.setTargetFile(resFile); - sLastResFilePath.put(mProject.getFullPath().toPortableString(), resFile); - - if (ref.isResIdDuplicate(resFile, text)) { - setMessage( - String.format("There's already a string item called '%1$s' in %2$s.", - text, resFile), - WizardPage.WARNING); - } else if (mProject.findMember(resFile) == null) { - setMessage( - String.format("File %2$s does not exist and will be created.", - text, resFile), - WizardPage.INFORMATION); - } else { - setMessage(null); - } - } - - setPageComplete(success); - return success; + public void postValidatePage(ValidationStatus status) { + ExtractStringRefactoring ref = getOurRefactoring(); + ref.setTargetFile(mImpl.getResFileProjPath()); } - - public class OnConfigSelectorUpdated implements Runnable, ModifyListener { - - /** Regex pattern to parse a valid res path: it reads (/res/folder-name/)+(filename). */ - private final Pattern mPathRegex = Pattern.compile( - "(/res/[a-z][a-zA-Z0-9_-]+/)(.+)"); //$NON-NLS-1$ - - /** Temporary config object used to retrieve the Config Selector value. */ - private FolderConfiguration mTempConfig = new FolderConfiguration(); - - private HashMap> mFolderCache = - new HashMap>(); - private String mLastFolderUsedInCombo = null; - private boolean mInternalConfigChange; - private boolean mInternalFileComboChange; - - /** - * Callback invoked when the {@link ConfigurationSelector} has been changed. - *

- * The callback does the following: - *

    - *
  • Examine the current file name to retrieve the XML filename, if any. - *
  • Recompute the path based on the configuration selector (e.g. /res/values-fr/). - *
  • Examine the path to retrieve all the files in it. Keep those in a local cache. - *
  • If the XML filename from step 1 is not in the file list, it's a custom file name. - * Insert it and sort it. - *
  • Re-populate the file combo with all the choices. - *
  • Select the original XML file. - */ - public void run() { - if (mInternalConfigChange) { - return; - } - - // get current leafname, if any - String leafName = ""; - String currPath = mResFileCombo.getText(); - Matcher m = mPathRegex.matcher(currPath); - if (m.matches()) { - // Note: groups 1 and 2 cannot be null. - leafName = m.group(2); - currPath = m.group(1); - } else { - // There was a path but it was invalid. Ignore it. - currPath = ""; - } - - // recreate the res path from the current configuration - mConfigSelector.getConfiguration(mTempConfig); - StringBuffer sb = new StringBuffer(RES_FOLDER_ABS); - sb.append(mTempConfig.getFolderName(ResourceFolderType.VALUES)); - sb.append('/'); - - String newPath = sb.toString(); - if (newPath.equals(currPath) && newPath.equals(mLastFolderUsedInCombo)) { - // Path has not changed. No need to reload. - return; - } - - // Get all the files at the new path - - TreeSet filePaths = mFolderCache.get(newPath); - - if (filePaths == null) { - filePaths = new TreeSet(); - - IFolder folder = mProject.getFolder(newPath); - if (folder != null && folder.exists()) { - try { - for (IResource res : folder.members()) { - String name = res.getName(); - if (res.getType() == IResource.FILE && name.endsWith(".xml")) { - filePaths.add(newPath + name); - } - } - } catch (CoreException e) { - // Ignore. - } - } - - mFolderCache.put(newPath, filePaths); - } - - currPath = newPath + leafName; - if (leafName.length() > 0 && !filePaths.contains(currPath)) { - filePaths.add(currPath); - } - - // Fill the combo - try { - mInternalFileComboChange = true; - - mResFileCombo.removeAll(); - - for (String filePath : filePaths) { - mResFileCombo.add(filePath); - } - - int index = -1; - if (leafName.length() > 0) { - index = mResFileCombo.indexOf(currPath); - if (index >= 0) { - mResFileCombo.select(index); - } - } - - if (index == -1) { - mResFileCombo.setText(currPath); - } - - mLastFolderUsedInCombo = newPath; - - } finally { - mInternalFileComboChange = false; - } - - // finally validate the whole page - validatePage(); - } - - /** - * Callback invoked when {@link ExtractStringInputPage#mResFileCombo} has been - * modified. - */ - public void modifyText(ModifyEvent e) { - if (mInternalFileComboChange) { - return; - } - - String wsFolderPath = mResFileCombo.getText(); - - // This is a custom path, we need to sanitize it. - // First it should start with "/res/". Then we need to make sure there are no - // relative paths, things like "../" or "./" or even "//". - wsFolderPath = wsFolderPath.replaceAll("/+\\.\\./+|/+\\./+|//+|\\\\+|^/+", "/"); //$NON-NLS-1$ //$NON-NLS-2$ - wsFolderPath = wsFolderPath.replaceAll("^\\.\\./+|^\\./+", ""); //$NON-NLS-1$ //$NON-NLS-2$ - wsFolderPath = wsFolderPath.replaceAll("/+\\.\\.$|/+\\.$|/+$", ""); //$NON-NLS-1$ //$NON-NLS-2$ - - // We get "res/foo" from selections relative to the project when we want a "/res/foo" path. - if (wsFolderPath.startsWith(RES_FOLDER_REL)) { - wsFolderPath = RES_FOLDER_ABS + wsFolderPath.substring(RES_FOLDER_REL.length()); - - mInternalFileComboChange = true; - mResFileCombo.setText(wsFolderPath); - mInternalFileComboChange = false; - } - - if (wsFolderPath.startsWith(RES_FOLDER_ABS)) { - wsFolderPath = wsFolderPath.substring(RES_FOLDER_ABS.length()); - - int pos = wsFolderPath.indexOf(AndroidConstants.WS_SEP_CHAR); - if (pos >= 0) { - wsFolderPath = wsFolderPath.substring(0, pos); - } - - String[] folderSegments = wsFolderPath.split(FolderConfiguration.QUALIFIER_SEP); - - if (folderSegments.length > 0) { - String folderName = folderSegments[0]; - - if (folderName != null && !folderName.equals(wsFolderPath)) { - // update config selector - mInternalConfigChange = true; - mConfigSelector.setConfiguration(folderSegments); - mInternalConfigChange = false; - } - } - } - - validatePage(); - } - } - } diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/refactorings/extractstring/ExtractStringRefactoring.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/refactorings/extractstring/ExtractStringRefactoring.java index 430ff1819..a17d81790 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/refactorings/extractstring/ExtractStringRefactoring.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/refactorings/extractstring/ExtractStringRefactoring.java @@ -16,9 +16,9 @@ package com.android.ide.eclipse.adt.refactorings.extractstring; +import com.android.ide.eclipse.adt.wizards.newstring.NewStringHelper; import com.android.ide.eclipse.common.AndroidConstants; import com.android.ide.eclipse.common.project.AndroidManifestParser; -import com.android.ide.eclipse.common.project.AndroidXPathFactory; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IProject; @@ -64,8 +64,6 @@ import org.eclipse.text.edits.MultiTextEdit; import org.eclipse.text.edits.ReplaceEdit; import org.eclipse.text.edits.TextEdit; import org.eclipse.text.edits.TextEditGroup; -import org.w3c.dom.NodeList; -import org.xml.sax.InputSource; import java.io.BufferedReader; import java.io.IOException; @@ -73,14 +71,9 @@ import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpressionException; - /** * This refactoring extracts a string from a file and replaces it by an Android resource ID * such as R.string.foo. @@ -105,8 +98,8 @@ import javax.xml.xpath.XPathExpressionException; *
  • On success, the wizard is shown, which let the user input the new ID to use. *
  • The wizard sets the user input values into this refactoring instance, e.g. the new string * ID, the XML file to update, etc. The wizard does use the utility method - * {@link #isResIdDuplicate(String, String)} to check whether the new ID is already defined - * in the target XML file. + * {@link NewStringHelper#isResIdDuplicate(IProject, String, String)} to check whether the new + * ID is already defined in the target XML file. *
  • Once Preview or Finish is selected in the wizard, the * {@link #checkFinalConditions(IProgressMonitor)} is called to double-check the user input * and compute the actual changes. @@ -127,60 +120,106 @@ import javax.xml.xpath.XPathExpressionException; *
  • TODO: Have a pref in the wizard: [x] Change other Java Files *
*/ -class ExtractStringRefactoring extends Refactoring { +public class ExtractStringRefactoring extends Refactoring { - /** The file model being manipulated. */ + private enum Mode { + EDIT_SOURCE, + MAKE_ID, + MAKE_NEW_ID + } + + /** The {@link Mode} of operation of the refactoring. */ + private final Mode mMode; + /** The file model being manipulated. + * Value is null when not on {@link Mode#EDIT_SOURCE} mode. */ private final IFile mFile; - /** The start of the selection in {@link #mFile}. */ + /** The start of the selection in {@link #mFile}. + * Value is -1 when not on {@link Mode#EDIT_SOURCE} mode. */ private final int mSelectionStart; - /** The end of the selection in {@link #mFile}. */ + /** The end of the selection in {@link #mFile}. + * Value is -1 when not on {@link Mode#EDIT_SOURCE} mode. */ private final int mSelectionEnd; /** The compilation unit, only defined if {@link #mFile} points to a usable Java source file. */ private ICompilationUnit mUnit; - /** The actual string selected, after UTF characters have been escaped, good for display. */ + /** The actual string selected, after UTF characters have been escaped, good for display. + * Value is null when not on {@link Mode#EDIT_SOURCE} mode. */ private String mTokenString; /** The XML string ID selected by the user in the wizard. */ private String mXmlStringId; + /** The XML string value. Might be different than the initial selected string. */ + private String mXmlStringValue; /** The path of the XML file that will define {@link #mXmlStringId}, selected by the user * in the wizard. */ private String mTargetXmlFileWsPath; - /** A temporary cache of R.string IDs defined by a given xml file. The key is the - * project path of the file, the data is a set of known string Ids for that file. */ - private HashMap> mResIdCache; - /** An instance of XPath, created lazily on demand. */ - private XPath mXPath; /** The list of changes computed by {@link #checkFinalConditions(IProgressMonitor)} and * used by {@link #createChange(IProgressMonitor)}. */ private ArrayList mChanges; + + private NewStringHelper mHelper = new NewStringHelper(); public ExtractStringRefactoring(Map arguments) throws NullPointerException { - - IPath path = Path.fromPortableString(arguments.get("file")); //$NON-NLS-1$ - mFile = (IFile) ResourcesPlugin.getWorkspace().getRoot().findMember(path); - mSelectionStart = Integer.parseInt(arguments.get("sel-start")); //$NON-NLS-1$ - mSelectionEnd = Integer.parseInt(arguments.get("sel-end")); //$NON-NLS-1$ - mTokenString = arguments.get("tok-esc"); //$NON-NLS-1$ + mMode = Mode.valueOf(arguments.get("mode")); //$NON-NLS-1$ + + if (mMode == Mode.EDIT_SOURCE) { + IPath path = Path.fromPortableString(arguments.get("file")); //$NON-NLS-1$ + mFile = (IFile) ResourcesPlugin.getWorkspace().getRoot().findMember(path); + mSelectionStart = Integer.parseInt(arguments.get("sel-start")); //$NON-NLS-1$ + mSelectionEnd = Integer.parseInt(arguments.get("sel-end")); //$NON-NLS-1$ + mTokenString = arguments.get("tok-esc"); //$NON-NLS-1$ + } else { + mFile = null; + mSelectionStart = mSelectionEnd = -1; + mTokenString = null; + } } private Map createArgumentMap() { HashMap args = new HashMap(); - args.put("file", mFile.getFullPath().toPortableString()); //$NON-NLS-1$ - args.put("sel-start", Integer.toString(mSelectionStart)); //$NON-NLS-1$ - args.put("sel-end", Integer.toString(mSelectionEnd)); //$NON-NLS-1$ - args.put("tok-esc", mTokenString); //$NON-NLS-1$ + args.put("mode", mMode.name()); //$NON-NLS-1$ + if (mMode == Mode.EDIT_SOURCE) { + args.put("file", mFile.getFullPath().toPortableString()); //$NON-NLS-1$ + args.put("sel-start", Integer.toString(mSelectionStart)); //$NON-NLS-1$ + args.put("sel-end", Integer.toString(mSelectionEnd)); //$NON-NLS-1$ + args.put("tok-esc", mTokenString); //$NON-NLS-1$ + } return args; } + /** + * Constructor to use when the Extract String refactoring is called on an + * *existing* source file. Its purpose is then to get the selected string of + * the source and propose to change it by an XML id. The XML id may be a new one + * or an existing one. + * + * @param file The source file to process. Cannot be null. File must exist in workspace. + * @param selection The selection in the source file. Cannot be null or empty. + */ public ExtractStringRefactoring(IFile file, ITextSelection selection) { + mMode = Mode.EDIT_SOURCE; mFile = file; mSelectionStart = selection.getOffset(); mSelectionEnd = mSelectionStart + Math.max(0, selection.getLength() - 1); } + /** + * Constructor to use when the Extract String refactoring is called without + * any source file. Its purpose is then to create a new XML string ID. + * + * @param enforceNew If true the XML ID must be a new one. If false, an existing ID can be + * used. + */ + public ExtractStringRefactoring(boolean enforceNew) { + mMode = enforceNew ? Mode.MAKE_NEW_ID : Mode.MAKE_ID; + mFile = null; + mSelectionStart = mSelectionEnd = -1; + } + + + /** * @see org.eclipse.ltk.core.refactoring.Refactoring#getName() */ @@ -225,6 +264,11 @@ class ExtractStringRefactoring extends Refactoring { try { monitor.beginTask("Checking preconditions...", 5); + + if (mMode != Mode.EDIT_SOURCE) { + monitor.worked(5); + return status; + } if (!checkSourceFile(mFile, status, monitor)) { return status; @@ -388,7 +432,7 @@ class ExtractStringRefactoring extends Refactoring { status.addFatalError("Missing target xml file path"); } monitor.worked(1); - + // Either that resource must not exist or it must be a writeable file. IResource targetXml = getTargetXmlResource(mTargetXmlFileWsPath); if (targetXml != null) { @@ -415,9 +459,9 @@ class ExtractStringRefactoring extends Refactoring { // Prepare the change for the XML file. - if (!isResIdDuplicate(mTargetXmlFileWsPath, mXmlStringId)) { + if (!mHelper.isResIdDuplicate(mFile.getProject(), mTargetXmlFileWsPath, mXmlStringId)) { // We actually change it only if the ID doesn't exist yet - Change change = createXmlChange((IFile) targetXml, mXmlStringId, mTokenString, + Change change = createXmlChange((IFile) targetXml, mXmlStringId, mXmlStringValue, status, SubMonitor.convert(monitor, 1)); if (change != null) { mChanges.add(change); @@ -427,12 +471,14 @@ class ExtractStringRefactoring extends Refactoring { if (status.hasError()) { return status; } - - // Prepare the change to the Java compilation unit - List changes = computeJavaChanges(mUnit, mXmlStringId, mTokenString, - status, SubMonitor.convert(monitor, 1)); - if (changes != null) { - mChanges.addAll(changes); + + if (mMode == Mode.EDIT_SOURCE) { + // Prepare the change to the Java compilation unit + List changes = computeJavaChanges(mUnit, mXmlStringId, mTokenString, + status, SubMonitor.convert(monitor, 1)); + if (changes != null) { + mChanges.addAll(changes); + } } monitor.worked(1); @@ -484,6 +530,9 @@ class ExtractStringRefactoring extends Refactoring { // The file exist. Attempt to parse it as a valid XML document. try { int[] indices = new int[2]; + + // TODO case where we replace the value of an existing XML String ID + if (findXmlOpeningTagPos(targetXml.getContents(), "resources", indices)) { //$NON-NLS-1$ // Indices[1] indicates whether we found > or />. It can only be 1 or 2. // Indices[0] is the position of the first character of either > or />. @@ -865,78 +914,6 @@ class ExtractStringRefactoring extends Refactoring { } - /** - * Utility method used by the wizard to check whether the given string ID is already - * defined in the XML file which path is given. - * - * @param xmlFileWsPath The project path of the XML file, e.g. "/res/values/strings.xml". - * The given file may or may not exist. - * @param stringId The string ID to find. - * @return True if such a string ID is already defined. - */ - public boolean isResIdDuplicate(String xmlFileWsPath, String stringId) { - // This is going to be called many times on the same file. - // Build a cache of the existing IDs for a given file. - if (mResIdCache == null) { - mResIdCache = new HashMap>(); - } - HashSet cache = mResIdCache.get(xmlFileWsPath); - if (cache == null) { - cache = getResIdsForFile(xmlFileWsPath); - mResIdCache.put(xmlFileWsPath, cache); - } - - return cache.contains(stringId); - } - - /** - * Extract all the defined string IDs from a given file using XPath. - * - * @param xmlFileWsPath The project path of the file to parse. It may not exist. - * @return The set of all string IDs defined in the file. The returned set is always non - * null. It is empty if the file does not exist. - */ - private HashSet getResIdsForFile(String xmlFileWsPath) { - HashSet ids = new HashSet(); - - if (mXPath == null) { - mXPath = AndroidXPathFactory.newXPath(); - } - - // Access the project that contains the resource that contains the compilation unit - IResource resource = getTargetXmlResource(xmlFileWsPath); - - if (resource != null && resource.exists() && resource.getType() == IResource.FILE) { - InputSource source; - try { - source = new InputSource(((IFile) resource).getContents()); - - // We want all the IDs in an XML structure like this: - // - // something - // - - String xpathExpr = "/resources/string/@name"; //$NON-NLS-1$ - - Object result = mXPath.evaluate(xpathExpr, source, XPathConstants.NODESET); - if (result instanceof NodeList) { - NodeList list = (NodeList) result; - for (int n = list.getLength() - 1; n >= 0; n--) { - String id = list.item(n).getNodeValue(); - ids.add(id); - } - } - - } catch (CoreException e1) { - // IFile.getContents failed. Ignore. - } catch (XPathExpressionException e) { - // mXPath.evaluate failed. Ignore. - } - } - - return ids; - } - /** * Given a file project path, returns its resource in the same project than the * compilation unit. The resource may not exist. @@ -950,8 +927,15 @@ class ExtractStringRefactoring extends Refactoring { /** * Sets the replacement string ID. Used by the wizard to set the user input. */ - public void setReplacementStringId(String replacementStringId) { - mXmlStringId = replacementStringId; + public void setNewStringId(String newStringId) { + mXmlStringId = newStringId; + } + + /** + * Sets the replacement string ID. Used by the wizard to set the user input. + */ + public void setNewStringValue(String newStringValue) { + mXmlStringValue = newStringValue; } /** diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/refactorings/extractstring/ExtractStringWizard.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/refactorings/extractstring/ExtractStringWizard.java index c5b0c7d11..cfcc54621 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/refactorings/extractstring/ExtractStringWizard.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/refactorings/extractstring/ExtractStringWizard.java @@ -25,7 +25,7 @@ import org.eclipse.ltk.ui.refactoring.RefactoringWizard; * @see ExtractStringInputPage * @see ExtractStringRefactoring */ -class ExtractStringWizard extends RefactoringWizard { +public class ExtractStringWizard extends RefactoringWizard { private final IProject mProject; diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/ui/ReferenceChooserDialog.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/ui/ReferenceChooserDialog.java index e141396c5..031b30382 100644 --- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/ui/ReferenceChooserDialog.java +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/ui/ReferenceChooserDialog.java @@ -17,10 +17,13 @@ package com.android.ide.eclipse.adt.ui; import com.android.ide.eclipse.adt.AdtPlugin; +import com.android.ide.eclipse.adt.refactorings.extractstring.ExtractStringRefactoring; +import com.android.ide.eclipse.adt.refactorings.extractstring.ExtractStringWizard; import com.android.ide.eclipse.common.resources.IResourceRepository; import com.android.ide.eclipse.common.resources.ResourceItem; import com.android.ide.eclipse.common.resources.ResourceType; +import org.eclipse.core.resources.IProject; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jface.dialogs.DialogSettings; @@ -30,14 +33,20 @@ import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.TreePath; import org.eclipse.jface.viewers.TreeSelection; import org.eclipse.jface.viewers.TreeViewer; +import org.eclipse.ltk.ui.refactoring.RefactoringWizard; +import org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation; import org.eclipse.swt.SWT; +import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Tree; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.PlatformUI; import org.eclipse.ui.dialogs.FilteredTree; import org.eclipse.ui.dialogs.PatternFilter; import org.eclipse.ui.dialogs.SelectionStatusDialog; @@ -58,21 +67,24 @@ public class ReferenceChooserDialog extends SelectionStatusDialog { private IResourceRepository mResources; private String mCurrentResource; - private FilteredTree mFilteredTree; + private Button mNewResButton; + private final IProject mProject; /** + * @param project * @param parent */ - public ReferenceChooserDialog(IResourceRepository resources, Shell parent) { + public ReferenceChooserDialog(IProject project, IResourceRepository resources, Shell parent) { super(parent); + mProject = project; + mResources = resources; int shellStyle = getShellStyle(); setShellStyle(shellStyle | SWT.MAX | SWT.RESIZE); - setTitle("Reference Dialog"); + setTitle("Reference Chooser"); setMessage(String.format("Choose a resource")); - mResources = resources; setDialogBoundsSettings(sDialogSettings, getDialogBoundsStrategy()); } @@ -113,13 +125,26 @@ public class ReferenceChooserDialog extends SelectionStatusDialog { // create the filtered tree createFilteredTree(top); - + // setup the initial selection setupInitialSelection(); + // create the "New Resource" button + createNewResButtons(top); + return top; } + /** + * Creates the "New Resource" button. + * @param top the parent composite + */ + private void createNewResButtons(Composite top) { + mNewResButton = new Button(top, SWT.NONE); + mNewResButton.addSelectionListener(new OnNewResButtonSelected()); + updateNewResButton(); + } + private void createFilteredTree(Composite parent) { mFilteredTree = new FilteredTree(parent, SWT.BORDER | SWT.SINGLE | SWT.FULL_SELECTION, new PatternFilter()); @@ -154,6 +179,7 @@ public class ReferenceChooserDialog extends SelectionStatusDialog { protected void handleSelection() { validateCurrentSelection(); + updateNewResButton(); } protected void handleDoubleClick() { @@ -205,6 +231,65 @@ public class ReferenceChooserDialog extends SelectionStatusDialog { return status.isOK(); } + + /** + * Updates the new res button when the list selection changes. + * The name of the button changes depending on the resource. + */ + private void updateNewResButton() { + ResourceType type = getSelectedResourceType(); + + // We only support adding new strings right now + mNewResButton.setEnabled(type == ResourceType.STRING); + + String title = String.format("New %1$s", type == null ? "Resource" : type.getDisplayName()); + mNewResButton.setText(title); + } + + /** + * Callback invoked when the mNewResButton is selected by the user. + */ + private class OnNewResButtonSelected extends SelectionAdapter { + @Override + public void widgetSelected(SelectionEvent e) { + super.widgetSelected(e); + + ResourceType type = getSelectedResourceType(); + + // We currently only support strings + if (type == ResourceType.STRING) { + + ExtractStringRefactoring ref = new ExtractStringRefactoring(true /*enforceNew*/); + RefactoringWizard wizard = new ExtractStringWizard(ref, mProject); + RefactoringWizardOpenOperation op = new RefactoringWizardOpenOperation(wizard); + try { + IWorkbench w = PlatformUI.getWorkbench(); + op.run(w.getDisplay().getActiveShell(), wizard.getDefaultPageTitle()); + + // TODO Select string + } catch (InterruptedException ex) { + // Interrupted. Pass. + } + } + } + } + + /** + * Returns the {@link ResourceType} of the selected element, if any. + * Returns null if nothing suitable is selected. + */ + private ResourceType getSelectedResourceType() { + ResourceType type = null; + + TreePath selection = getSelection(); + if (selection != null && selection.getSegmentCount() > 0) { + Object first = selection.getFirstSegment(); + if (first instanceof ResourceType) { + type = (ResourceType) first; + } + } + return type; + } /** * Sets up the initial selection. diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newstring/NewStringBaseImpl.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newstring/NewStringBaseImpl.java new file mode 100644 index 000000000..334b13387 --- /dev/null +++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newstring/NewStringBaseImpl.java @@ -0,0 +1,439 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Eclipse Public License, Version 1.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.eclipse.org/org/documents/epl-v10.php + * + * 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. + */ + +package com.android.ide.eclipse.adt.wizards.newstring; + + +import com.android.ide.eclipse.adt.ui.ConfigurationSelector; +import com.android.ide.eclipse.common.AndroidConstants; +import com.android.ide.eclipse.editors.resources.configurations.FolderConfiguration; +import com.android.ide.eclipse.editors.resources.manager.ResourceFolderType; +import com.android.sdklib.SdkConstants; + +import org.eclipse.core.resources.IFolder; +import org.eclipse.core.resources.IProject; +import org.eclipse.core.resources.IResource; +import org.eclipse.core.runtime.CoreException; +import org.eclipse.jface.wizard.WizardPage; +import org.eclipse.swt.SWT; +import org.eclipse.swt.events.ModifyEvent; +import org.eclipse.swt.events.ModifyListener; +import org.eclipse.swt.layout.GridData; +import org.eclipse.swt.layout.GridLayout; +import org.eclipse.swt.widgets.Combo; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Group; +import org.eclipse.swt.widgets.Label; +import org.eclipse.swt.widgets.Text; + +import java.util.HashMap; +import java.util.TreeSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class NewStringBaseImpl { + + public interface INewStringPageCallback { + /** + * Creates the top group with the field to replace which string and by what + * and by which options. + * + * @param content A composite with a 1-column grid layout + * @return The {@link Text} field for the new String ID name. + */ + public Text createStringGroup(Composite content); + + /** Implements {@link WizardPage#setErrorMessage(String)} */ + public void setErrorMessage(String newMessage); + /** Implements {@link WizardPage#setMessage(String, int)} */ + public void setMessage(String msg, int type); + /** Implements {@link WizardPage#setPageComplete(boolean)} */ + public void setPageComplete(boolean success); + + public void postValidatePage(ValidationStatus status); + } + + public class ValidationStatus { + private String mError = null; + private String mMessage = null; + public int mMessageType = WizardPage.NONE; + + public boolean success() { + return getError() != null; + } + + public void setError(String error) { + mError = error; + mMessageType = WizardPage.ERROR; + } + + public String getError() { + return mError; + } + + public void setMessage(String msg, int type) { + mMessage = msg; + mMessageType = type; + } + + public String getMessage() { + return mMessage; + } + + public int getMessageType() { + return mMessageType; + } + } + + /** Last res file path used, shared across the session instances but specific to the + * current project. The default for unknown projects is {@link #DEFAULT_RES_FILE_PATH}. */ + private static HashMap sLastResFilePath = new HashMap(); + + /** The project where the user selection happened. */ + private final IProject mProject; + /** Text field where the user enters the new ID. */ + private Text mStringIdField; + /** The configuration selector, to select the resource path of the XML file. */ + private ConfigurationSelector mConfigSelector; + /** The combo to display the existing XML files or enter a new one. */ + private Combo mResFileCombo; + + private NewStringHelper mHelper = new NewStringHelper(); + + /** Regex pattern to read a valid res XML file path. It checks that the are 2 folders and + * a leaf file name ending with .xml */ + private static final Pattern RES_XML_FILE_REGEX = Pattern.compile( + "/res/[a-z][a-zA-Z0-9_-]+/[^.]+\\.xml"); //$NON-NLS-1$ + /** Absolute destination folder root, e.g. "/res/" */ + private static final String RES_FOLDER_ABS = + AndroidConstants.WS_RESOURCES + AndroidConstants.WS_SEP; + /** Relative destination folder root, e.g. "res/" */ + private static final String RES_FOLDER_REL = + SdkConstants.FD_RESOURCES + AndroidConstants.WS_SEP; + + private static final String DEFAULT_RES_FILE_PATH = "/res/values/strings.xml"; //$NON-NLS-1$ + + private final INewStringPageCallback mWizardPage; + + public NewStringBaseImpl(IProject project, INewStringPageCallback wizardPage) { + mProject = project; + mWizardPage = wizardPage; + } + + /** + * Create the UI for the new string wizard. + */ + public void createControl(Composite parent) { + mStringIdField = mWizardPage.createStringGroup(parent); + createResFileGroup(parent); + } + + /** + * Creates the lower group with the fields to choose the resource confirmation and + * the target XML file. + * + * @param content A composite with a 1-column grid layout + */ + private void createResFileGroup(Composite content) { + + Group group = new Group(content, SWT.NONE); + group.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + group.setText("XML resource to edit"); + + GridLayout layout = new GridLayout(); + layout.numColumns = 2; + group.setLayout(layout); + + // line: selection of the res config + + Label label; + label = new Label(group, SWT.NONE); + label.setText("Configuration:"); + + mConfigSelector = new ConfigurationSelector(group); + GridData gd = new GridData(2, GridData.GRAB_HORIZONTAL | GridData.GRAB_VERTICAL); + gd.widthHint = ConfigurationSelector.WIDTH_HINT; + gd.heightHint = ConfigurationSelector.HEIGHT_HINT; + mConfigSelector.setLayoutData(gd); + OnConfigSelectorUpdated onConfigSelectorUpdated = new OnConfigSelectorUpdated(); + mConfigSelector.setOnChangeListener(onConfigSelectorUpdated); + + // line: selection of the output file + + label = new Label(group, SWT.NONE); + label.setText("Resource file:"); + + mResFileCombo = new Combo(group, SWT.DROP_DOWN); + mResFileCombo.select(0); + mResFileCombo.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); + mResFileCombo.addModifyListener(onConfigSelectorUpdated); + + // set output file name to the last one used + + String projPath = mProject.getFullPath().toPortableString(); + String filePath = sLastResFilePath.get(projPath); + + mResFileCombo.setText(filePath != null ? filePath : DEFAULT_RES_FILE_PATH); + onConfigSelectorUpdated.run(); + } + + /** + * Validates fields of the wizard input page. Displays errors as appropriate and + * enable the "Next" button (or not) by calling + * {@link INewStringPageCallback#setPageComplete(boolean)}. + * + * @return True if the page has been positively validated. It may still have warnings. + */ + public boolean validatePage() { + ValidationStatus status = new ValidationStatus(); + + validateStringFields(status); + if (status.success()) { + validatePathFields(status); + } + + mWizardPage.postValidatePage(status); + + mWizardPage.setErrorMessage(status.getError()); + mWizardPage.setMessage(status.getMessage(), status.getMessageType()); + mWizardPage.setPageComplete(status.success()); + return status.success(); + } + + public void validateStringFields(ValidationStatus status) { + + String text = mStringIdField.getText().trim(); + if (text == null || text.length() < 1) { + status.setError("Please provide a resource ID to replace with."); + } else { + for (int i = 0; i < text.length(); i++) { + char c = text.charAt(i); + boolean ok = i == 0 ? + Character.isJavaIdentifierStart(c) : + Character.isJavaIdentifierPart(c); + if (!ok) { + status.setError(String.format( + "The resource ID must be a valid Java identifier. The character %1$c at position %2$d is not acceptable.", + c, i+1)); + break; + } + } + } + } + + public ValidationStatus validatePathFields(ValidationStatus status) { + String resFile = getResFileProjPath(); + if (resFile == null || resFile.length() == 0) { + status.setError("A resource file name is required."); + } else if (!RES_XML_FILE_REGEX.matcher(resFile).matches()) { + status.setError("The XML file name is not valid."); + } + + if (status.success()) { + sLastResFilePath.put(mProject.getFullPath().toPortableString(), resFile); + + String text = mStringIdField.getText().trim(); + + if (mHelper.isResIdDuplicate(mProject, resFile, text)) { + status.setMessage( + String.format("There's already a string item called '%1$s' in %2$s.", + text, resFile), WizardPage.WARNING); + } else if (mProject.findMember(resFile) == null) { + status.setMessage( + String.format("File %2$s does not exist and will be created.", + text, resFile), WizardPage.INFORMATION); + } + } + + return status; + } + + public String getResFileProjPath() { + return mResFileCombo.getText().trim(); + } + + public class OnConfigSelectorUpdated implements Runnable, ModifyListener { + + /** Regex pattern to parse a valid res path: it reads (/res/folder-name/)+(filename). */ + private final Pattern mPathRegex = Pattern.compile( + "(/res/[a-z][a-zA-Z0-9_-]+/)(.+)"); //$NON-NLS-1$ + + /** Temporary config object used to retrieve the Config Selector value. */ + private FolderConfiguration mTempConfig = new FolderConfiguration(); + + private HashMap> mFolderCache = + new HashMap>(); + private String mLastFolderUsedInCombo = null; + private boolean mInternalConfigChange; + private boolean mInternalFileComboChange; + + /** + * Callback invoked when the {@link ConfigurationSelector} has been changed. + *

+ * The callback does the following: + *