From ebaef5ec19e687a76c74fcc1ef07113f88c0aaea Mon Sep 17 00:00:00 2001 From: Amith Yamasani <> Date: Tue, 31 Mar 2009 14:14:19 -0700 Subject: [PATCH 01/12] AI 143689: am: CL 143659 am: CL 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. Original author: yamasani Merged from: //branches/cupcake/... Original author: android-build Merged from: //branches/donutburger/... Automated import of CL 143689 --- .../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 11fcb514390397d327f90625e00b2c69a71af8c4 Mon Sep 17 00:00:00 2001 From: Raphael Moll <> Date: Tue, 31 Mar 2009 14:16:11 -0700 Subject: [PATCH 02/12] AI 143693: am: CL 143665 am: CL 143491 ADT #1742875: Document the SDK build process and new cupcake SDK changes. Original author: raphael Merged from: //branches/cupcake/... Original author: android-build Merged from: //branches/donutburger/... Automated import of CL 143693 --- 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 363efea89cf714b6eeb5808d01cc025065ce2858 Mon Sep 17 00:00:00 2001 From: Xavier Ducrohet <> Date: Tue, 31 Mar 2009 14:18:00 -0700 Subject: [PATCH 03/12] AI 143701: am: CL 143672 am: CL 143499 Fix the icon for the JUnit launch shortcut Original author: xav Merged from: //branches/cupcake/... Original author: android-build Merged from: //branches/donutburger/... Automated import of CL 143701 --- 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 9bec3079c9aafcf936d77bea4603e5c4588e80a2 Mon Sep 17 00:00:00 2001 From: Brett Chabot <> Date: Tue, 31 Mar 2009 14:21:33 -0700 Subject: [PATCH 04/12] AI 143713: am: CL 143688 am: CL 143562 Usability fixes for runtest.py Original author: brettchabot Merged from: //branches/cupcake/... Original author: android-build Merged from: //branches/donutburger/... Automated import of CL 143713 --- 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 94967f1cd63fe0b9bd8aebcf1feb909e7b626a72 Mon Sep 17 00:00:00 2001 From: Yu Shan Emily Lau <> Date: Tue, 31 Mar 2009 14:25:11 -0700 Subject: [PATCH 05/12] AI 143717: am: CL 143698 am: CL 143596 Removed all the obsoleted media related functional test suite. (incl, very old meidaProvider, RingToneSettings and the flaky Music Player test. Original author: yslau Merged from: //branches/cupcake/... Original author: android-build Merged from: //branches/donutburger/... Automated import of CL 143717 --- 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 42ab43b51ad7b1523a48c456cb62cfff50a45f4f Mon Sep 17 00:00:00 2001 From: Raphael Moll <> Date: Tue, 31 Mar 2009 14:48:14 -0700 Subject: [PATCH 06/12] AI 143828: am: CL 143808 am: CL 143754 SdkManager: list unknown AVDs and why they didn't load. Original author: raphael Merged from: //branches/cupcake/... Original author: android-build Merged from: //branches/donutburger/... Automated import of CL 143828 --- .../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 a3a8aeb15c4e7b80428bdc1726d7b24a1b6206ec Mon Sep 17 00:00:00 2001 From: Brett Chabot <> Date: Tue, 31 Mar 2009 14:51:13 -0700 Subject: [PATCH 07/12] AI 143831: am: CL 143819 am: CL 143765 Rename tests.xml to test_defs.xml Original author: brettchabot Merged from: //branches/cupcake/... Original author: android-build Merged from: //branches/donutburger/... Automated import of CL 143831 --- 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 ba5dfbf9f4b87308c1cc8d986f4bd94520013472 Mon Sep 17 00:00:00 2001 From: Jeffrey Sharkey <> Date: Tue, 31 Mar 2009 17:01:02 -0700 Subject: [PATCH 08/12] AI 143867: am: CL 143865 am: CL 143864 Fix SDK example to correctly pass back newly-configured appWidgetId. Original author: jsharkey Merged from: //branches/cupcake/... Original author: android-build Merged from: //branches/donutburger/... Automated import of CL 143867 --- .../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 dc9a9a7bf7ea12241af3bd431de758676e57ccf1 Mon Sep 17 00:00:00 2001 From: Raphael Moll <> Date: Tue, 31 Mar 2009 17:20:54 -0700 Subject: [PATCH 09/12] AI 143880: am: CL 143879 am: CL 143876 Include hprof-conv in SDK (bug #1640225) Original author: raphael Merged from: //branches/cupcake/... Original author: android-build Merged from: //branches/donutburger/... Automated import of CL 143880 --- 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 4ca8a78df757937e3f57d1ed54803a9945077443 Mon Sep 17 00:00:00 2001 From: Raphael Moll <> Date: Tue, 31 Mar 2009 17:24:12 -0700 Subject: [PATCH 10/12] AI 143885: am: CL 143883 am: CL 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. Original author: raphael Merged from: //branches/cupcake/... Original author: android-build Merged from: //branches/donutburger/... Automated import of CL 143885 --- .../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 99a0b5c4a2f8aac752fdb1f1480de45defbe9746 Mon Sep 17 00:00:00 2001 From: Raphael Moll <> Date: Tue, 31 Mar 2009 17:26:38 -0700 Subject: [PATCH 11/12] AI 143887: am: CL 143886 am: CL 143882 ADT #1743364: Refactor misc UI widgets together in package adt.ui. Original author: raphael Merged from: //branches/cupcake/... Original author: android-build Merged from: //branches/donutburger/... Automated import of CL 143887 --- .../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 ac2a8469f27968904243b98d1546a12825178a11 Mon Sep 17 00:00:00 2001 From: Brett Chabot <> Date: Tue, 31 Mar 2009 19:16:14 -0700 Subject: [PATCH 12/12] AI 143919: am: CL 143918 am: CL 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. Original author: brettchabot Merged from: //branches/cupcake/... Original author: android-build Merged from: //branches/donutburger/... Automated import of CL 143919 --- .../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);