diff --git a/apps/Development/AndroidManifest.xml b/apps/Development/AndroidManifest.xml
index 9c6b92b28..7bf840440 100644
--- a/apps/Development/AndroidManifest.xml
+++ b/apps/Development/AndroidManifest.xml
@@ -123,13 +123,15 @@
-
+
+
diff --git a/apps/Fallback/res/values-cs/strings.xml b/apps/Fallback/res/values-cs/strings.xml
new file mode 100644
index 000000000..b7e114ff1
--- /dev/null
+++ b/apps/Fallback/res/values-cs/strings.xml
@@ -0,0 +1,7 @@
+
+
+ "Záloha"
+ "Akce není podporována"
+ "Tato akce není momentálně podporována."
+
diff --git a/apps/Fallback/res/values-es/strings.xml b/apps/Fallback/res/values-es/strings.xml
new file mode 100644
index 000000000..f0de2b6d5
--- /dev/null
+++ b/apps/Fallback/res/values-es/strings.xml
@@ -0,0 +1,7 @@
+
+
+ "Fallback"
+ "Acción no admitida"
+ "Esa acción no se admite actualmente."
+
diff --git a/apps/Fallback/res/values-nl/strings.xml b/apps/Fallback/res/values-nl/strings.xml
new file mode 100644
index 000000000..d0fa5e16e
--- /dev/null
+++ b/apps/Fallback/res/values-nl/strings.xml
@@ -0,0 +1,7 @@
+
+
+ "Reserve"
+ "Niet-ondersteunde actie"
+ "Die actie wordt momenteel niet ondersteund."
+
diff --git a/apps/Fallback/res/values-pl/strings.xml b/apps/Fallback/res/values-pl/strings.xml
new file mode 100644
index 000000000..c63bf61f9
--- /dev/null
+++ b/apps/Fallback/res/values-pl/strings.xml
@@ -0,0 +1,7 @@
+
+
+ "Wycofanie"
+ "Nieobsługiwana czynność"
+ "Ta czynność nie jest aktualnie obsługiwana."
+
diff --git a/apps/Fallback/res/values-ru/strings.xml b/apps/Fallback/res/values-ru/strings.xml
new file mode 100644
index 000000000..088fc6f1b
--- /dev/null
+++ b/apps/Fallback/res/values-ru/strings.xml
@@ -0,0 +1,7 @@
+
+
+ "Fallback"
+ "Действие не поддерживается"
+ "В настоящее время это действие не поддерживается."
+
diff --git a/apps/Fallback/res/values-zh-rTW/strings.xml b/apps/Fallback/res/values-zh-rTW/strings.xml
new file mode 100644
index 000000000..ec10a8348
--- /dev/null
+++ b/apps/Fallback/res/values-zh-rTW/strings.xml
@@ -0,0 +1,7 @@
+
+
+ "備用"
+ "不支援的操作"
+ "目前不支援此操作。"
+
diff --git a/apps/SdkSetup/AndroidManifest.xml b/apps/SdkSetup/AndroidManifest.xml
index 9cd20a82d..966eeb106 100644
--- a/apps/SdkSetup/AndroidManifest.xml
+++ b/apps/SdkSetup/AndroidManifest.xml
@@ -17,7 +17,8 @@
-
+
+
diff --git a/build/tools/make_windows_sdk.sh b/build/tools/make_windows_sdk.sh
index f49165ce3..4f3cee815 100755
--- a/build/tools/make_windows_sdk.sh
+++ b/build/tools/make_windows_sdk.sh
@@ -78,9 +78,11 @@ function package() {
unzip "$SDK_ZIP" -d "$DIST_DIR"
mv -v "$UNZIPPED" "$DEST"
- # USB Driver is not in tools
- mkdir -pv $DEST/usb_driver
- cp -rv development/host/windows/prebuilt/usb/driver/* $DEST/usb_driver
+ # USB Driver for ADB
+ mkdir -pv $DEST/usb_driver/x86
+ cp -rv development/host/windows/prebuilt/usb/driver/* $DEST/usb_driver/x86/
+ mkdir -pv $DEST/usb_driver/amd64
+ cp -rv development/host/windows/prebuilt/usb/driver_amd_64/* $DEST/usb_driver/amd64/
# Remove obsolete stuff from tools
TOOLS="$DEST/tools"
diff --git a/emulator/qemud/qemud.c b/emulator/qemud/qemud.c
index 3a53716b8..ae6797e21 100644
--- a/emulator/qemud/qemud.c
+++ b/emulator/qemud/qemud.c
@@ -1250,7 +1250,7 @@ static Multiplexer _multiplexer[1];
static const struct { const char* name; ChannelType ctype; } default_channels[] = {
{ "gsm", CHANNEL_DUPLEX }, /* GSM AT command channel, used by commands/rild/rild.c */
- { "gps", CHANNEL_BROADCAST }, /* GPS NMEA commands, used by libs/hardware/qemu_gps.c */
+ { "gps", CHANNEL_BROADCAST }, /* GPS NMEA commands, used by libs/hardware_legacy/qemu_gps.c */
{ "control", CHANNEL_DUPLEX }, /* Used for power/leds/vibrator/etc... */
{ NULL, 0 }
};
diff --git a/host/windows/prebuilt/usb/AdbWinApi.dll b/host/windows/prebuilt/usb/AdbWinApi.dll
index aa8e9568a..1626bce4b 100755
Binary files a/host/windows/prebuilt/usb/AdbWinApi.dll and b/host/windows/prebuilt/usb/AdbWinApi.dll differ
diff --git a/host/windows/prebuilt/usb/driver/android_usb.inf b/host/windows/prebuilt/usb/driver/android_usb.inf
index 69a94911b..2837a1bc9 100644
--- a/host/windows/prebuilt/usb/driver/android_usb.inf
+++ b/host/windows/prebuilt/usb/driver/android_usb.inf
@@ -10,8 +10,9 @@ Signature="$WINDOWS NT$"
Class=USB
ClassGuid={F72FE0D4-CBCB-407d-8814-9ED673D0DD6B}
Provider=%GOOG%
-DriverVer=date,1.0.0009.00000
-CatalogFile=androidusb.cat
+DriverVer=12/11/2008,1.0.0009.00000
+CatalogFile.NTx86=androidusb86.cat
+CatalogFile.NTamd64=androidusba64.cat
; ================= Class section =====================
@@ -28,7 +29,7 @@ DefaultDestDir = 12
; ================= Device section =====================
[Manufacturer]
-%MfgName%=Google,NTx86
+%MfgName%=Google,NTx86,NTamd64
; For Win2K
[Google]
@@ -46,6 +47,14 @@ DefaultDestDir = 12
%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
+; For AMD64 and later
+[Google.NTamd64]
+; For loopback testing
+%USB\VID_18D1&PID_DDDD.DeviceDescTest%=androidusb.Dev, USB\VID_18D1&PID_DDDD
+; HTC Dream
+%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
+%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
+
[androidusb.Dev.NT]
CopyFiles=androidusb.Files.Ext
diff --git a/host/windows/prebuilt/usb/driver/androidusb.sys b/host/windows/prebuilt/usb/driver/androidusb.sys
index ebd01b88d..fe6453178 100644
Binary files a/host/windows/prebuilt/usb/driver/androidusb.sys and b/host/windows/prebuilt/usb/driver/androidusb.sys differ
diff --git a/host/windows/prebuilt/usb/driver/androidusb86.cat b/host/windows/prebuilt/usb/driver/androidusb86.cat
new file mode 100644
index 000000000..12836dcf7
Binary files /dev/null and b/host/windows/prebuilt/usb/driver/androidusb86.cat differ
diff --git a/host/windows/prebuilt/usb/driver_amd_64/WdfCoInstaller01005.dll b/host/windows/prebuilt/usb/driver_amd_64/WdfCoInstaller01005.dll
new file mode 100644
index 000000000..32519fb68
Binary files /dev/null and b/host/windows/prebuilt/usb/driver_amd_64/WdfCoInstaller01005.dll differ
diff --git a/host/windows/prebuilt/usb/driver_amd_64/android_usb.inf b/host/windows/prebuilt/usb/driver_amd_64/android_usb.inf
new file mode 100644
index 000000000..2837a1bc9
--- /dev/null
+++ b/host/windows/prebuilt/usb/driver_amd_64/android_usb.inf
@@ -0,0 +1,122 @@
+;/*++
+;
+;Abstract:
+; Installation inf for the Android USB Bulk device
+;
+;--*/
+
+[Version]
+Signature="$WINDOWS NT$"
+Class=USB
+ClassGuid={F72FE0D4-CBCB-407d-8814-9ED673D0DD6B}
+Provider=%GOOG%
+DriverVer=12/11/2008,1.0.0009.00000
+CatalogFile.NTx86=androidusb86.cat
+CatalogFile.NTamd64=androidusba64.cat
+
+; ================= Class section =====================
+
+[ClassInstall32]
+Addreg=AndroidUsbClassReg
+
+[AndroidUsbClassReg]
+HKR,,,0,%ClassName%
+HKR,,Icon,,-5
+
+[DestinationDirs]
+DefaultDestDir = 12
+
+; ================= Device section =====================
+
+[Manufacturer]
+%MfgName%=Google,NTx86,NTamd64
+
+; For Win2K
+[Google]
+; For loopback testing
+%USB\VID_18D1&PID_DDDD.DeviceDescTest%=androidusb.Dev, USB\VID_18D1&PID_DDDD
+; HTC Dream
+%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
+%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
+
+; For XP and later
+[Google.NTx86]
+; For loopback testing
+%USB\VID_18D1&PID_DDDD.DeviceDescTest%=androidusb.Dev, USB\VID_18D1&PID_DDDD
+; HTC Dream
+%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
+%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
+
+; For AMD64 and later
+[Google.NTamd64]
+; For loopback testing
+%USB\VID_18D1&PID_DDDD.DeviceDescTest%=androidusb.Dev, USB\VID_18D1&PID_DDDD
+; HTC Dream
+%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
+%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
+
+[androidusb.Dev.NT]
+CopyFiles=androidusb.Files.Ext
+
+[androidusb.Dev.NT.Services]
+Addservice = androidusb, 0x00000002, androidusb.AddService
+
+[androidusb.AddService]
+DisplayName = %androidusb.SvcDesc%
+ServiceType = 1 ; SERVICE_KERNEL_DRIVER
+StartType = 3 ; SERVICE_DEMAND_START
+ErrorControl = 1 ; SERVICE_ERROR_NORMAL
+ServiceBinary = %10%\System32\Drivers\androidusb.sys
+AddReg = androidusb.AddReg
+LoadOrderGroup = Base
+
+[androidusb.AddReg]
+HKR,"Parameters","MaximumTransferSize",0x10001,4096
+HKR,"Parameters","DebugLevel",0x10001,2
+HKR, Parameters\Wdf, VerboseOn, 0x00010001, 1
+HKR, Parameters\Wdf, VerifierOn, 0x00010001, 1
+HKR, Parameters\Wdf, DbgBreakOnError, 0x00010001, 1
+
+[androidusb.Files.Ext]
+androidusb.sys
+
+[SourceDisksNames]
+1=%Disk_Description%,,,
+
+[SourceDisksFiles]
+androidusb.sys = 1
+
+;-------------- WDF Coinstaller installation
+[DestinationDirs]
+CoInstaller_CopyFiles = 11
+
+[androidusb.Dev.NT.CoInstallers]
+AddReg=CoInstaller_AddReg
+CopyFiles=CoInstaller_CopyFiles
+
+[CoInstaller_CopyFiles]
+wdfcoinstaller01005.dll
+
+[SourceDisksFiles]
+wdfcoinstaller01005.dll=1 ; make sure the number matches with SourceDisksNames
+
+[CoInstaller_AddReg]
+HKR,,CoInstallers32,0x00010000, "wdfcoinstaller01005.dll,WdfCoInstaller"
+
+[androidusb.Dev.NT.Wdf]
+KmdfService = androidusb, androidusb_wdfsect
+
+[androidusb_wdfsect]
+KmdfLibraryVersion = 1.5
+
+;---------------------------------------------------------------;
+
+[Strings]
+GOOG = "Google, Inc"
+MfgName = "Google, Inc"
+Disk_Description= "ADB Interface Installation Disk"
+androidusb.SvcDesc = "ADB Interface Driver"
+ClassName = "ADB Interface"
+USB\VID_18D1&PID_DDDD.DeviceDescTest="ADB Testing Interface"
+USB\VID_0BB4&PID_0C01.DeviceDescRelease="HTC Dream"
+USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease="HTC Dream Composite ADB Interface"
diff --git a/host/windows/prebuilt/usb/driver_amd_64/androidusb.sys b/host/windows/prebuilt/usb/driver_amd_64/androidusb.sys
new file mode 100644
index 000000000..70ce24fd1
Binary files /dev/null and b/host/windows/prebuilt/usb/driver_amd_64/androidusb.sys differ
diff --git a/host/windows/prebuilt/usb/driver_amd_64/androidusba64.cat b/host/windows/prebuilt/usb/driver_amd_64/androidusba64.cat
new file mode 100644
index 000000000..9d5db5d1f
Binary files /dev/null and b/host/windows/prebuilt/usb/driver_amd_64/androidusba64.cat differ
diff --git a/host/windows/usb/api/AdbWinApi.vcproj b/host/windows/usb/api/AdbWinApi.vcproj
index f9d15e5f6..c8dfe5509 100644
--- a/host/windows/usb/api/AdbWinApi.vcproj
+++ b/host/windows/usb/api/AdbWinApi.vcproj
@@ -1,290 +1,290 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/host/windows/usb/api/adb_api_extra.h b/host/windows/usb/api/adb_api_extra.h
index cad480dcd..e644b015f 100644
--- a/host/windows/usb/api/adb_api_extra.h
+++ b/host/windows/usb/api/adb_api_extra.h
@@ -67,19 +67,22 @@ typedef struct _AdbEndpointInformation {
{0xf72fe0d4, 0xcbcb, 0x407d, {0x88, 0x14, 0x9e, 0xd6, 0x73, 0xd0, 0xdd, 0x6b}};
/// Defines vendor ID for the device
-#define DEVICE_VENDOR_ID 0x18D1
+#define DEVICE_VENDOR_ID 0x0BB4
/// Defines product ID for the device with single interface.
-#define DEVICE_SINGLE_PRODUCT_ID 0xD00D
+#define DEVICE_SINGLE_PRODUCT_ID 0x0C01
/// Defines product ID for the composite device.
-#define DEVICE_COMPOSITE_PRODUCT_ID 0xDEED
+#define DEVICE_COMPOSITE_PRODUCT_ID 0x0C02
+
+/// Defines interface ID for the device.
+#define DEVICE_INTERFACE_ID 0x01
+
+/// Defines vendor ID for the device
+#define DEVICE_EMULATOR_VENDOR_ID 0x18D1
/// Defines product ID for a SoftUSB device simulator that is used to test
/// the driver in isolation from hardware.
#define DEVICE_EMULATOR_PROD_ID 0xDDDD
-/// Defines interface ID for the device.
-#define DEVICE_INTERFACE_ID 0x01
-
#endif // ANDROID_USB_API_ADB_API_EXTRA_H__
diff --git a/host/windows/usb/api/adb_io_object.cpp b/host/windows/usb/api/adb_io_object.cpp
index ea4bc8f72..732dc22b6 100644
--- a/host/windows/usb/api/adb_io_object.cpp
+++ b/host/windows/usb/api/adb_io_object.cpp
@@ -191,7 +191,7 @@ ADBAPIHANDLE AdbIOObject::CommonAsyncReadWrite(bool is_read,
AdbBulkTransfer transfer_param;
transfer_param.time_out = time_out;
transfer_param.transfer_size = is_read ? 0 : bytes_to_transfer;
- transfer_param.write_buffer = is_read ? NULL : buffer;
+ transfer_param.SetWriteBuffer(is_read ? NULL : buffer);
res = DeviceIoControl(usb_handle(),
is_read ? ADB_IOCTL_BULK_READ : ADB_IOCTL_BULK_WRITE,
@@ -254,7 +254,7 @@ bool AdbIOObject::CommonSyncReadWrite(bool is_read,
AdbBulkTransfer transfer_param;
transfer_param.time_out = time_out;
transfer_param.transfer_size = is_read ? 0 : bytes_to_transfer;
- transfer_param.write_buffer = is_read ? NULL : buffer;
+ transfer_param.SetWriteBuffer(is_read ? NULL : buffer);
ULONG tmp;
ret = DeviceIoControl(usb_handle(),
diff --git a/host/windows/usb/common/android_usb_common_defines.h b/host/windows/usb/common/android_usb_common_defines.h
index abdeba782..723f4a356 100644
--- a/host/windows/usb/common/android_usb_common_defines.h
+++ b/host/windows/usb/common/android_usb_common_defines.h
@@ -60,35 +60,35 @@
CTL_CODE(FILE_DEVICE_UNKNOWN, \
ADB_CTL_GET_USB_DEVICE_DESCRIPTOR, \
METHOD_BUFFERED, \
- FILE_ANY_ACCESS)
+ FILE_READ_ACCESS)
/// IOCTL that gets USB_CONFIGURATION_DESCRIPTOR
#define ADB_IOCTL_GET_USB_CONFIGURATION_DESCRIPTOR \
CTL_CODE(FILE_DEVICE_UNKNOWN, \
ADB_CTL_GET_USB_CONFIGURATION_DESCRIPTOR, \
METHOD_BUFFERED, \
- FILE_ANY_ACCESS)
+ FILE_READ_ACCESS)
/// IOCTL that gets USB_INTERFACE_DESCRIPTOR
#define ADB_IOCTL_GET_USB_INTERFACE_DESCRIPTOR \
CTL_CODE(FILE_DEVICE_UNKNOWN, \
ADB_CTL_GET_USB_INTERFACE_DESCRIPTOR, \
METHOD_BUFFERED, \
- FILE_ANY_ACCESS)
+ FILE_READ_ACCESS)
/// IOCTL that gets endpoint information
#define ADB_IOCTL_GET_ENDPOINT_INFORMATION \
CTL_CODE(FILE_DEVICE_UNKNOWN, \
ADB_CTL_GET_ENDPOINT_INFORMATION, \
METHOD_BUFFERED, \
- FILE_ANY_ACCESS)
+ FILE_READ_ACCESS)
/// Bulk read IOCTL
#define ADB_IOCTL_BULK_READ \
CTL_CODE(FILE_DEVICE_UNKNOWN, \
ADB_CTL_BULK_READ, \
METHOD_OUT_DIRECT, \
- FILE_ANY_ACCESS)
+ FILE_READ_ACCESS)
// For bulk write IOCTL we send request data in the form of AdbBulkTransfer
// structure and output buffer is just ULONG that receives number of bytes
@@ -99,14 +99,14 @@
CTL_CODE(FILE_DEVICE_UNKNOWN, \
ADB_CTL_BULK_WRITE, \
METHOD_BUFFERED, \
- FILE_ANY_ACCESS)
+ FILE_WRITE_ACCESS)
/// IOCTL that gets device serial number
#define ADB_IOCTL_GET_SERIAL_NUMBER \
CTL_CODE(FILE_DEVICE_UNKNOWN, \
ADB_CTL_GET_SERIAL_NUMBER, \
METHOD_BUFFERED, \
- FILE_ANY_ACCESS)
+ FILE_READ_ACCESS)
///@}
@@ -131,9 +131,49 @@ struct AdbBulkTransfer {
/// size is defined by the output buffer size.
ULONG transfer_size;
+ /// Initializes statically allocated structure
+ __forceinline AdbBulkTransfer() {
+ time_out = 0;
+ transfer_size = 0;
+ for_x64 = 0;
+ }
+
+ /// Provides access to protected write_buffer field
+ void* GetWriteBuffer() {
+ return write_buffer;
+ }
+
+ /// Provides access to protected write_buffer field
+ const void* GetWriteBuffer() const {
+ return write_buffer;
+ }
+
+ /// Sets write_buffer field.
+ void SetWriteBuffer(void* buffer) {
+ // For 32-bit we must zero out high 32 bit of the address, so 64-bit
+ // driver will see valid address when accessing 64-bit write_buffer.
+ for_x64 = 0;
+ write_buffer = buffer;
+ }
+
+protected:
/// Pointer to the actual buffer for ADB_CTL_BULK_WRITE request. This field
- /// is not used in ADB_CTL_BULK_READ request.
- void* write_buffer;
+ /// is not used in ADB_CTL_BULK_READ request. Note that in order to support
+ /// compatibility between 32-bit and 64-bit versions of both, driver and
+ /// application we must sizeof this field to the max pointer sizeof (which
+ /// is 64 bit in our case). The idea is that if IOCTL was issued by a 64-bit
+ /// process to a 64-bit driver, write_buffer will be valid 64-bit pointer to
+ /// the write buffer. Same is true for 32-bit app talking to 32-bit driver.
+ /// If, however, a 32-bit app is talking to 64-bit driver, then write_buffer
+ /// initialized by 32-bit app will contain 32-bit address, which will be
+ /// correctly picked up ("extended") by 64-bit driver. Since when setting
+ /// this field by a 32-bit app requires some extra work (see SetWriteBuffer)
+ /// we hide this field, making it accessible only throug the accessor
+ /// methods (Get/SetWriteBuffer).
+ union {
+ void* write_buffer;
+ __int64 for_x64;
+ };
};
#endif // ANDROID_USB_COMMON_DEFINES_H__
diff --git a/host/windows/usb/driver/android_usb.inf b/host/windows/usb/driver/android_usb.inf
index 69a94911b..2837a1bc9 100644
--- a/host/windows/usb/driver/android_usb.inf
+++ b/host/windows/usb/driver/android_usb.inf
@@ -10,8 +10,9 @@ Signature="$WINDOWS NT$"
Class=USB
ClassGuid={F72FE0D4-CBCB-407d-8814-9ED673D0DD6B}
Provider=%GOOG%
-DriverVer=date,1.0.0009.00000
-CatalogFile=androidusb.cat
+DriverVer=12/11/2008,1.0.0009.00000
+CatalogFile.NTx86=androidusb86.cat
+CatalogFile.NTamd64=androidusba64.cat
; ================= Class section =====================
@@ -28,7 +29,7 @@ DefaultDestDir = 12
; ================= Device section =====================
[Manufacturer]
-%MfgName%=Google,NTx86
+%MfgName%=Google,NTx86,NTamd64
; For Win2K
[Google]
@@ -46,6 +47,14 @@ DefaultDestDir = 12
%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
+; For AMD64 and later
+[Google.NTamd64]
+; For loopback testing
+%USB\VID_18D1&PID_DDDD.DeviceDescTest%=androidusb.Dev, USB\VID_18D1&PID_DDDD
+; HTC Dream
+%USB\VID_0BB4&PID_0C01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C01
+%USB\VID_0BB4&PID_0C02&MI_01.DeviceDescRelease%=androidusb.Dev, USB\VID_0BB4&PID_0C02&MI_01
+
[androidusb.Dev.NT]
CopyFiles=androidusb.Files.Ext
diff --git a/host/windows/usb/driver/android_usb.sln b/host/windows/usb/driver/android_usb.sln
index 1c5193e38..ac4cbe901 100644
--- a/host/windows/usb/driver/android_usb.sln
+++ b/host/windows/usb/driver/android_usb.sln
@@ -6,13 +6,19 @@ EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
+ Debug-64 = Debug-64
Release = Release
+ Release-64 = Release-64
EndGlobalSection
GlobalSection(ProjectConfiguration) = postSolution
{D980BE56-A7AB-4E05-919B-677FB7716307}.Debug.ActiveCfg = Debug|Win32
{D980BE56-A7AB-4E05-919B-677FB7716307}.Debug.Build.0 = Debug|Win32
+ {D980BE56-A7AB-4E05-919B-677FB7716307}.Debug-64.ActiveCfg = Debug-64|Win32
+ {D980BE56-A7AB-4E05-919B-677FB7716307}.Debug-64.Build.0 = Debug-64|Win32
{D980BE56-A7AB-4E05-919B-677FB7716307}.Release.ActiveCfg = Release|Win32
{D980BE56-A7AB-4E05-919B-677FB7716307}.Release.Build.0 = Release|Win32
+ {D980BE56-A7AB-4E05-919B-677FB7716307}.Release-64.ActiveCfg = Release-64|Win32
+ {D980BE56-A7AB-4E05-919B-677FB7716307}.Release-64.Build.0 = Release-64|Win32
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
diff --git a/host/windows/usb/driver/android_usb.vcproj b/host/windows/usb/driver/android_usb.vcproj
index 5c21aa463..5402b0c2b 100644
--- a/host/windows/usb/driver/android_usb.vcproj
+++ b/host/windows/usb/driver/android_usb.vcproj
@@ -18,33 +18,36 @@
ConfigurationType="0">
+build -c0"/>
+build -c0"/>
+
+
+
+
+
+
@@ -749,10 +836,10 @@ build -c0
RelativePath="..\..\..\..\Winddk\6000\inc\api\usb.h">
+ RelativePath="..\..\..\..\Winddk\6000\inc\api\usb100.h">
+ RelativePath="..\..\..\..\..\..\..\..\Winddk\6000\inc\api\usb100.h">
@@ -794,10 +881,10 @@ build -c0
RelativePath="..\..\..\..\Winddk\6000\inc\ddk\videoagp.h">
+ RelativePath="..\..\..\..\..\..\..\..\Winddk\6000\inc\wdf\kmdf\10\wdf.h">
+ RelativePath="..\..\..\..\Winddk\6000\inc\wdf\kmdf\10\wdf.h">
@@ -805,252 +892,252 @@ build -c0
-
-
+ RelativePath="..\..\..\..\Winddk\6000\inc\wdf\kmdf\10\wdf11.h">
+
+
-
-
+ RelativePath="..\..\..\..\..\..\..\..\Winddk\6000\inc\wdf\kmdf\10\wdfchildlist.h">
+ RelativePath="..\..\..\..\..\..\..\..\Winddk\6000\inc\wdf\kmdf\10\wdfcollection.h">
+ RelativePath="..\..\..\..\..\..\..\..\Winddk\6000\inc\wdf\kmdf\10\wdfcommonbuffer.h">
+
+
-
-
+ RelativePath="..\..\..\..\Winddk\6000\inc\wdf\kmdf\10\wdfdevice.h">
+ RelativePath="..\..\..\..\..\..\..\..\Winddk\6000\inc\wdf\kmdf\10\wdfdmaenabler.h">
+ RelativePath="..\..\..\..\..\..\..\..\Winddk\6000\inc\wdf\kmdf\10\wdfdmatransaction.h">
+
+
-
-
+ RelativePath="..\..\..\..\..\..\..\..\Winddk\6000\inc\wdf\kmdf\10\wdffdo.h">
+
+
-
-
+ RelativePath="..\..\..\..\..\..\..\..\Winddk\6000\inc\wdf\kmdf\10\wdfglobals.h">
+
+
-
-
+ RelativePath="..\..\..\..\..\..\..\..\Winddk\6000\inc\wdf\kmdf\10\wdfio.h">
+ RelativePath="..\..\..\..\Winddk\6000\inc\wdf\kmdf\10\wdfiotarget.h">
+ RelativePath="..\..\..\..\Winddk\6000\inc\wdf\kmdf\10\wdfmemory.h">
+
+
-
-
+ RelativePath="..\..\..\..\..\..\..\..\Winddk\6000\inc\wdf\kmdf\10\wdfpdo.h">
+ RelativePath="..\..\..\..\..\..\..\..\Winddk\6000\inc\wdf\kmdf\10\wdfpool.h">
+ RelativePath="..\..\..\..\..\..\..\..\Winddk\6000\inc\wdf\kmdf\10\wdfqueryinterface.h">
+
+
-
-
+ RelativePath="..\..\..\..\..\..\..\..\Winddk\6000\inc\wdf\kmdf\10\wdfresource.h">
+ RelativePath="..\..\..\..\..\..\..\..\Winddk\6000\inc\wdf\kmdf\10\wdfstatus.h">
+ RelativePath="..\..\..\..\..\..\..\..\Winddk\6000\inc\wdf\kmdf\10\wdfstring.h">
+
+
-
-
+ RelativePath="..\..\..\..\..\..\..\..\Winddk\6000\inc\wdf\kmdf\10\wdftraceenums.h">
+ RelativePath="..\..\..\..\..\..\..\..\Winddk\6000\inc\wdf\kmdf\10\wdftypes.h">
+ RelativePath="..\..\..\..\Winddk\6000\inc\wdf\kmdf\10\wdfusb.h">
+
+
-
-
+ RelativePath="..\..\..\..\Winddk\6000\inc\wdf\kmdf\10\wdfworkitem.h">
+
+
diff --git a/host/windows/usb/driver/android_usb_device_file_object.cpp b/host/windows/usb/driver/android_usb_device_file_object.cpp
index 0655aed93..e134ebb4c 100644
--- a/host/windows/usb/driver/android_usb_device_file_object.cpp
+++ b/host/windows/usb/driver/android_usb_device_file_object.cpp
@@ -47,26 +47,26 @@ void AndroidUsbDeviceFileObject::OnEvtIoDeviceControl(WDFREQUEST request,
ULONG ioctl_code) {
ASSERT_IRQL_LOW_OR_DISPATCH();
- switch (GetCtlCode(ioctl_code)) {
- case ADB_CTL_GET_USB_DEVICE_DESCRIPTOR:
+ switch (ioctl_code) {
+ case ADB_IOCTL_GET_USB_DEVICE_DESCRIPTOR:
device_object()->OnGetUsbDeviceDescriptorCtl(request, output_buf_len);
break;
- case ADB_CTL_GET_USB_CONFIGURATION_DESCRIPTOR:
+ case ADB_IOCTL_GET_USB_CONFIGURATION_DESCRIPTOR:
device_object()->OnGetUsbConfigDescriptorCtl(request, output_buf_len);
break;
- case ADB_CTL_GET_USB_INTERFACE_DESCRIPTOR:
+ case ADB_IOCTL_GET_USB_INTERFACE_DESCRIPTOR:
device_object()->OnGetUsbInterfaceDescriptorCtl(request, output_buf_len);
break;
- case ADB_CTL_GET_ENDPOINT_INFORMATION:
+ case ADB_IOCTL_GET_ENDPOINT_INFORMATION:
device_object()->OnGetEndpointInformationCtl(request,
input_buf_len,
output_buf_len);
break;
- case ADB_CTL_GET_SERIAL_NUMBER:
+ case ADB_IOCTL_GET_SERIAL_NUMBER:
device_object()->OnGetSerialNumberCtl(request, output_buf_len);
break;
diff --git a/host/windows/usb/driver/android_usb_pipe_file_object.cpp b/host/windows/usb/driver/android_usb_pipe_file_object.cpp
index 08d01654e..384668348 100644
--- a/host/windows/usb/driver/android_usb_pipe_file_object.cpp
+++ b/host/windows/usb/driver/android_usb_pipe_file_object.cpp
@@ -143,16 +143,16 @@ void AndroidUsbPipeFileObject::OnEvtIoDeviceControl(WDFREQUEST request,
ULONG ioctl_code) {
ASSERT_IRQL_LOW_OR_DISPATCH();
- switch (GetCtlCode(ioctl_code)) {
- case ADB_CTL_GET_ENDPOINT_INFORMATION:
+ switch (ioctl_code) {
+ case ADB_IOCTL_GET_ENDPOINT_INFORMATION:
OnCtlGetEndpointInformation(request, output_buf_len);
break;
- case ADB_CTL_BULK_READ:
+ case ADB_IOCTL_BULK_READ:
OnCtlBulkRead(request, output_buf_len, input_buf_len);
break;
- case ADB_CTL_BULK_WRITE:
+ case ADB_IOCTL_BULK_WRITE:
OnCtlBulkWrite(request, output_buf_len, input_buf_len);
break;
@@ -300,7 +300,7 @@ void AndroidUsbPipeFileObject::OnCtlBulkWrite(WDFREQUEST request,
// 1. Never trust anything that comes from the User Mode.
// 2. Never assume that anything that User Mode buffer has will remain
// unchanged.
- void* transfer_buffer = transfer_param->write_buffer;
+ void* transfer_buffer = transfer_param->GetWriteBuffer();
ULONG transfer_size = transfer_param->transfer_size;
// Make sure zero length I/O doesn't go through
diff --git a/samples/NotePad/AndroidManifest.xml b/samples/NotePad/AndroidManifest.xml
index 84e87dd85..5c56dafa9 100644
--- a/samples/NotePad/AndroidManifest.xml
+++ b/samples/NotePad/AndroidManifest.xml
@@ -75,7 +75,8 @@
+ android:theme="@android:style/Theme.Dialog"
+ android:windowSoftInputMode="stateVisible">
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/samples/SimpleJNI/jni/Android.mk b/samples/SimpleJNI/jni/Android.mk
new file mode 100644
index 000000000..528196b0a
--- /dev/null
+++ b/samples/SimpleJNI/jni/Android.mk
@@ -0,0 +1,54 @@
+#
+# Copyright (C) 2008 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# This makefile supplies the rules for building a library of JNI code for
+# use by our example of how to bundle a shared library with an APK.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := samples
+
+# This is the target being built.
+LOCAL_MODULE:= libsimplejni
+
+
+# All of the source files that we will compile.
+LOCAL_SRC_FILES:= \
+ native.cpp
+
+# All of the shared libraries we link against.
+LOCAL_SHARED_LIBRARIES := \
+ libutils
+
+# No static libraries.
+LOCAL_STATIC_LIBRARIES :=
+
+# Also need the JNI headers.
+LOCAL_C_INCLUDES += \
+ $(JNI_H_INCLUDE)
+
+# No special compiler flags.
+LOCAL_CFLAGS +=
+
+# Don't prelink this library. For more efficient code, you may want
+# to add this library to the prelink map and set this to true. However,
+# it's difficult to do this for applications that are not supplied as
+# part of a system image.
+
+LOCAL_PRELINK_MODULE := false
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/samples/SimpleJNI/jni/native.cpp b/samples/SimpleJNI/jni/native.cpp
new file mode 100644
index 000000000..4d2e4e0bb
--- /dev/null
+++ b/samples/SimpleJNI/jni/native.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+#define LOG_TAG "simplejni native.cpp"
+#include
+
+#include
+
+#include "jni.h"
+
+static jint
+add(JNIEnv *env, jobject thiz, jint a, jint b) {
+int result = a + b;
+ LOGI("%d + %d = %d", a, b, result);
+ return result;
+}
+
+static const char *classPathName = "com/example/android/simplejni/Native";
+
+static JNINativeMethod methods[] = {
+ {"add", "(II)I", (void*)add },
+};
+
+/*
+ * Register several native methods for one class.
+ */
+static int registerNativeMethods(JNIEnv* env, const char* className,
+ JNINativeMethod* gMethods, int numMethods)
+{
+ jclass clazz;
+
+ clazz = env->FindClass(className);
+ if (clazz == NULL) {
+ LOGE("Native registration unable to find class '%s'", className);
+ return JNI_FALSE;
+ }
+ if (env->RegisterNatives(clazz, gMethods, numMethods) < 0) {
+ LOGE("RegisterNatives failed for '%s'", className);
+ return JNI_FALSE;
+ }
+
+ return JNI_TRUE;
+}
+
+/*
+ * Register native methods for all classes we know about.
+ *
+ * returns JNI_TRUE on success.
+ */
+static int registerNatives(JNIEnv* env)
+{
+ if (!registerNativeMethods(env, classPathName,
+ methods, sizeof(methods) / sizeof(methods[0]))) {
+ return JNI_FALSE;
+ }
+
+ return JNI_TRUE;
+}
+
+
+// ----------------------------------------------------------------------------
+
+/*
+ * This is called by the VM when the shared library is first loaded.
+ */
+
+typedef union {
+ JNIEnv* env;
+ void* venv;
+} UnionJNIEnvToVoid;
+
+jint JNI_OnLoad(JavaVM* vm, void* reserved)
+{
+ UnionJNIEnvToVoid uenv;
+ uenv.venv = NULL;
+ jint result = -1;
+ JNIEnv* env = NULL;
+
+ LOGI("JNI_OnLoad");
+
+ if (vm->GetEnv(&uenv.venv, JNI_VERSION_1_4) != JNI_OK) {
+ LOGE("ERROR: GetEnv failed");
+ goto bail;
+ }
+ env = uenv.env;
+
+ if (registerNatives(env) != JNI_TRUE) {
+ LOGE("ERROR: registerNatives failed");
+ goto bail;
+ }
+
+ result = JNI_VERSION_1_4;
+
+bail:
+ return result;
+}
diff --git a/samples/SimpleJNI/src/com/example/android/simplejni/SimpleJNI.java b/samples/SimpleJNI/src/com/example/android/simplejni/SimpleJNI.java
new file mode 100644
index 000000000..e83cd2117
--- /dev/null
+++ b/samples/SimpleJNI/src/com/example/android/simplejni/SimpleJNI.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2008 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.
+ */
+
+package com.example.android.simplejni;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.TextView;
+
+public class SimpleJNI extends Activity {
+ /** Called when the activity is first created. */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ TextView tv = new TextView(this);
+ int sum = Native.add(2, 3);
+ tv.setText("2 + 3 = " + Integer.toString(sum));
+ setContentView(tv);
+ }
+}
+
+class Native {
+ static {
+ // The runtime will add "lib" on the front and ".o" on the end of
+ // the name supplied to loadLibrary.
+ System.loadLibrary("simplejni");
+ }
+
+ static native int add(int a, int b);
+}
diff --git a/samples/Snake/AndroidManifest.xml b/samples/Snake/AndroidManifest.xml
index ce9b50b94..174e8b4be 100644
--- a/samples/Snake/AndroidManifest.xml
+++ b/samples/Snake/AndroidManifest.xml
@@ -22,7 +22,9 @@
-
+
diff --git a/samples/Snake/res/layout/snake_layout.xml b/samples/Snake/res/layout/snake_layout.xml
index 92d97ad1b..583c0c44d 100644
--- a/samples/Snake/res/layout/snake_layout.xml
+++ b/samples/Snake/res/layout/snake_layout.xml
@@ -22,7 +22,7 @@
android:id="@+id/snake"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
- tileSize="12"
+ tileSize="24"
/>
* Gets the project target hash string from {@link ProjectProperties#PROPERTY_TARGET},
- * and resolves it.
- * Sets up ant properties so that the rest of the Ant scripts finds:
- *
- * - Path to the underlying platform to access the build rules ('android-platform')
-
- *
- *
+ * and resolves it to get the project's {@link IAndroidTarget}.
+ * Sets up properties so that aapt can find the android.jar in the resolved target.
+ * Sets up the boot classpath ref so that the javac task knows where to find
+ * the libraries. This includes the default android.jar from the resolved target but also optional
+ * libraries provided by the target (if any, when the target is an add-on).
+ * Imports the build rules located in the resolved target so that the build actually does
+ * something.
*
*
* This is used in build.xml/template.
@@ -46,8 +51,12 @@ import java.util.ArrayList;
public class AndroidInitTask extends ImportTask {
private final static String ANDROID_RULES = "android_rules.xml";
+ // ant property with the path to the android.jar
private final static String PROPERTY_ANDROID_JAR = "android-jar";
+ // ant property with the path to the framework.jar
private final static String PROPERTY_ANDROID_AIDL = "android-aidl";
+ // ref id to the object containing all the boot classpaths.
+ private final static String REF_CLASSPATH = "android.target.classpath";
@Override
public void execute() throws BuildException {
@@ -117,13 +126,39 @@ public class AndroidInitTask extends ImportTask {
System.out.println("Platform Version: " + androidTarget.getApiVersionName());
System.out.println("API level: " + androidTarget.getApiVersionNumber());
- // sets up the properties.
+ // sets up the properties to find android.jar/framework.aidl
String androidJar = androidTarget.getPath(IAndroidTarget.ANDROID_JAR);
String androidAidl = androidTarget.getPath(IAndroidTarget.ANDROID_AIDL);
-
antProject.setProperty(PROPERTY_ANDROID_JAR, androidJar);
antProject.setProperty(PROPERTY_ANDROID_AIDL, androidAidl);
+
+ // sets up the boot classpath
+
+ // create the Path object
+ Path bootclasspath = new Path(antProject);
+
+ // create a PathElement for the framework jar
+ PathElement element = bootclasspath.createPathElement();
+ element.setPath(androidJar);
+ // create PathElement for each optional library.
+ IOptionalLibrary[] libraries = androidTarget.getOptionalLibraries();
+ if (libraries != null) {
+ HashSet visitedJars = new HashSet();
+ for (IOptionalLibrary library : libraries) {
+ String jarPath = library.getJarPath();
+ if (visitedJars.contains(jarPath) == false) {
+ visitedJars.add(jarPath);
+
+ element = bootclasspath.createPathElement();
+ element.setPath(library.getJarPath());
+ }
+ }
+ }
+
+ // finally sets the path in the project with a reference
+ antProject.addReference(REF_CLASSPATH, bootclasspath);
+
// find the file to import, and import it.
String templateFolder = androidTarget.getPath(IAndroidTarget.TEMPLATES);
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/.classpath b/tools/eclipse/plugins/com.android.ide.eclipse.adt/.classpath
index bbcdff971..c3c8c1004 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/.classpath
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/.classpath
@@ -10,7 +10,7 @@
-
-
+
+
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java
index e38419ad8..6743246b5 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/build/ApkBuilder.java
@@ -648,8 +648,11 @@ public class ApkBuilder extends BaseBuilder {
return false;
}
} catch (Throwable ex) {
- String message = String.format(Messages.Dalvik_Error_s,
- ex.getMessage());
+ String message = ex.getMessage();
+ if (message == null) {
+ message = ex.getClass().getCanonicalName();
+ }
+ message = String.format(Messages.Dalvik_Error_s, message);
AdtPlugin.printErrorToConsole(getProject(), message);
markProject(AdtConstants.MARKER_ADT, message, IMarker.SEVERITY_ERROR);
if ((ex instanceof NoClassDefFoundError)
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainer.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainer.java
index 945fe5244..c7cb42792 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainer.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainer.java
@@ -32,12 +32,12 @@ class AndroidClasspathContainer implements IClasspathContainer {
/**
* Constructs the container with the {@link IClasspathEntry} representing the android
* framework jar file and the container id
- * @param entry the entry representing the android framework.
+ * @param entries the entries representing the android framework and optional libraries.
* @param path the path containing the classpath container id.
* @param name the name of the container to display.
*/
- AndroidClasspathContainer(IClasspathEntry entry, IPath path, String name) {
- mClasspathEntry = new IClasspathEntry[] { entry };
+ AndroidClasspathContainer(IClasspathEntry[] entries, IPath path, String name) {
+ mClasspathEntry = entries;
mContainerPath = path;
mName = name;
}
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainerInitializer.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainerInitializer.java
index 4da216cd4..afa1fb54d 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainerInitializer.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/project/internal/AndroidClasspathContainerInitializer.java
@@ -22,6 +22,7 @@ import com.android.ide.eclipse.adt.sdk.LoadStatus;
import com.android.ide.eclipse.adt.sdk.Sdk;
import com.android.ide.eclipse.common.project.BaseProjectHelper;
import com.android.sdklib.IAndroidTarget;
+import com.android.sdklib.IAndroidTarget.IOptionalLibrary;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
@@ -43,6 +44,9 @@ import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
+import java.util.ArrayList;
+import java.util.HashSet;
+
/**
* Classpath container initializer responsible for binding {@link AndroidClasspathContainer} to
* {@link IProject}s. This removes the hard-coded path to the android.jar.
@@ -141,7 +145,6 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit
// just log the error
AdtPlugin.log(ce, "Error removing target marker.");
}
-
// First we check if the SDK has been loaded.
// By passing the javaProject to getSdkLoadStatus(), we ensure that, should the SDK
@@ -255,15 +258,19 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit
}
/**
- * Creates and returns a new {@link IClasspathEntry} object for the android
- * framework. This references the OS path to the android.jar and the
+ * Creates and returns an array of {@link IClasspathEntry} objects for the android
+ * framework and optional libraries.
+ * This references the OS path to the android.jar and the
* java doc directory. This is dynamically created when a project is opened,
* and never saved in the project itself, so there's no risk of storing an
* obsolete path.
*
* @param target The target that contains the libraries.
*/
- private static IClasspathEntry createFrameworkClasspath(IAndroidTarget target) {
+ private static IClasspathEntry[] createFrameworkClasspath(IAndroidTarget target) {
+ ArrayList list = new ArrayList();
+
+ // First, we create the IClasspathEntry for the framework.
// now add the android framework to the class path.
// create the path object.
IPath android_lib = new Path(target.getPath(IAndroidTarget.ANDROID_JAR));
@@ -278,14 +285,49 @@ public class AndroidClasspathContainerInitializer extends ClasspathContainerInit
new Path("com/android/internal/**"), //$NON-NLS-1$
IAccessRule.K_NON_ACCESSIBLE);
- IClasspathEntry classpathEntry = JavaCore.newLibraryEntry(android_lib,
+ IClasspathEntry frameworkClasspathEntry = JavaCore.newLibraryEntry(android_lib,
android_src, // source attachment path
null, // default source attachment root path.
new IAccessRule[] { accessRule },
new IClasspathAttribute[] { cpAttribute },
false // not exported.
);
+
+ list.add(frameworkClasspathEntry);
+
+ // now deal with optional libraries
+ IOptionalLibrary[] libraries = target.getOptionalLibraries();
+ if (libraries != null) {
+ HashSet visitedJars = new HashSet();
+ for (IOptionalLibrary library : libraries) {
+ String jarPath = library.getJarPath();
+ if (visitedJars.contains(jarPath) == false) {
+ visitedJars.add(jarPath);
- return classpathEntry;
+ // create the java doc link, if needed
+ String targetDocPath = target.getPath(IAndroidTarget.DOCS);
+ IClasspathAttribute[] attributes = null;
+ if (targetDocPath != null) {
+ attributes = new IClasspathAttribute[] {
+ JavaCore.newClasspathAttribute(
+ IClasspathAttribute.JAVADOC_LOCATION_ATTRIBUTE_NAME,
+ targetDocPath)
+ };
+ }
+
+ IClasspathEntry entry = JavaCore.newLibraryEntry(
+ new Path(library.getJarPath()),
+ null, // source attachment path
+ null, // default source attachment root path.
+ null,
+ attributes,
+ false // not exported.
+ );
+ list.add(entry);
+ }
+ }
+ }
+
+ return list.toArray(new IClasspathEntry[list.size()]);
}
}
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 19f8f4508..a0a3603fb 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
@@ -145,7 +145,9 @@ public class Sdk {
/**
* Returns a target from a hash that was generated by {@link IAndroidTarget#hashString()}.
- * @param hash the hash
+ *
+ * @param hash the {@link IAndroidTarget} hash string.
+ * @return The matching {@link IAndroidTarget} or null.
*/
public IAndroidTarget getTargetFromHashString(String hash) {
return mManager.getTargetFromHashString(hash);
diff --git a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectCreationPage.java b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectCreationPage.java
index 7fc94efd8..33ec2bcff 100644
--- a/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectCreationPage.java
+++ b/tools/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/wizards/newproject/NewProjectCreationPage.java
@@ -27,6 +27,8 @@ import com.android.ide.eclipse.common.AndroidConstants;
import com.android.ide.eclipse.common.project.AndroidManifestHelper;
import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.SdkConstants;
+import com.android.sdklib.project.ProjectProperties;
+import com.android.sdklib.project.ProjectProperties.PropertyType;
import com.android.sdkuilib.SdkTargetSelector;
import org.eclipse.core.filesystem.URIUtil;
@@ -129,6 +131,7 @@ public class NewProjectCreationPage extends WizardPage {
protected boolean mProjectNameModifiedByUser;
protected boolean mApplicationNameModifiedByUser;
private boolean mInternalMinSdkVersionUpdate;
+ private boolean mMinSdkVersionModifiedByUser;
/**
@@ -402,6 +405,7 @@ public class NewProjectCreationPage extends WizardPage {
mSdkTargetSelector.setSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent e) {
+ onSdkTargetModified();
updateLocationPathField(null);
setPageComplete(validatePage());
}
@@ -735,6 +739,14 @@ public class NewProjectCreationPage extends WizardPage {
try {
int version = Integer.parseInt(getMinSdkVersion());
+ // Before changing, compare with the currently selected one, if any.
+ // There can be multiple targets with the same sdk api version, so don't change
+ // it if it's already at the right version.
+ IAndroidTarget curr_target = getSdkTarget();
+ if (curr_target != null && curr_target.getApiVersionNumber() == version) {
+ return;
+ }
+
for (IAndroidTarget target : mSdkTargetSelector.getTargets()) {
if (target.getApiVersionNumber() == version) {
mSdkTargetSelector.setSelection(target);
@@ -744,6 +756,24 @@ public class NewProjectCreationPage extends WizardPage {
} catch (NumberFormatException e) {
// ignore
}
+
+ mMinSdkVersionModifiedByUser = true;
+ }
+
+ /**
+ * Called when an SDK target is modified.
+ *
+ * If the minSdkVersion field hasn't been modified by the user yet, we change it
+ * to reflect the sdk api level that has just been selected.
+ */
+ private void onSdkTargetModified() {
+ IAndroidTarget target = getSdkTarget();
+
+ if (target != null && !mMinSdkVersionModifiedByUser) {
+ mInternalMinSdkVersionUpdate = true;
+ mMinSdkVersionField.setText(Integer.toString(target.getApiVersionNumber()));
+ mInternalMinSdkVersionUpdate = false;
+ }
}
/**
@@ -872,9 +902,22 @@ public class NewProjectCreationPage extends WizardPage {
}
}
- // Select the target matching the manifest's sdk, if any
+ // Select the target matching the manifest's sdk or build properties, if any
boolean foundTarget = false;
- if (minSdkVersion != null) {
+
+ ProjectProperties p = ProjectProperties.create(projectLocation, null);
+ if (p != null) {
+ // Check the {build|default}.properties files if present
+ p.merge(PropertyType.BUILD).merge(PropertyType.DEFAULT);
+ String v = p.getProperty(ProjectProperties.PROPERTY_TARGET);
+ IAndroidTarget target = Sdk.getCurrent().getTargetFromHashString(v);
+ if (target != null) {
+ mSdkTargetSelector.setSelection(target);
+ foundTarget = true;
+ }
+ }
+
+ if (!foundTarget && minSdkVersion != null) {
try {
int sdkVersion = Integer.parseInt(minSdkVersion);
diff --git a/tools/runtest b/tools/runtest
index cc6444b31..989f8a493 100755
--- a/tools/runtest
+++ b/tools/runtest
@@ -17,7 +17,7 @@
# Options and default values
# TODO: other options ideas:
# pass options to am (then remove some of the more specific options)
-# TODO capture more non-error output when not -v
+# TODO capture more non-error output when not -v
# TODO read configs from vendor/*, not just from vendor/google
optListTests=0
@@ -53,8 +53,8 @@ function processOptions() {
t ) optTestMethod=${OPTARG} ;;
u ) optUserTests=${OPTARG} ;;
esac
- done
-}
+ done
+}
#
# Show the command usage and options
@@ -80,12 +80,12 @@ function showUsage() {
echo " short-test-name # (req'd) test configuration to launch" >&2
}
-# The list below are built-in test definitions. You can also define your own
-# tests by creating a file named "~/.android/runtest.rc" and adding them to that
+# The list below are built-in test definitions. You can also define your own
+# tests by creating a file named "~/.android/runtest.rc" and adding them to that
# file. (No array needed, just plain lines of text).
#
# Rests are defined by entries with the following format:
-#
+#
#
#
# These map to the following commands:
@@ -102,7 +102,7 @@ function showUsage() {
# = "#": test class is fully qualified with package
# = "#": skip build/sync step
# = "#": omit "-e class" section
-# = "#": use same value as test-package
+# = "#": use same value as test-package
# = "#": use "android.test.InstrumentationTestRunner"
#
# TODO: fields may be omitted completely if the trailing values are all "#"
@@ -123,6 +123,8 @@ knownTests=(
"heap frameworks/base/tests/AndroidTests com.android.unit_tests HeapTest # #"
"activity frameworks/base/tests/AndroidTests com.android.unit_tests activity.ActivityTests # #"
"deadlock tests/Deadlock com.android.deadlock # com.android.deadlock.tests #"
+ "syncadapter vendor/google/tests/AbstractGDataSyncAdapterTest # # com.google.android.providers.abstractgdatasyncadaptertests #"
+ "tablemerger frameworks/base/tests/FrameworkTest # android.content.AbstractTableMergerTest com.android.frameworktest.tests #"
# selected app tests
"browser packages/apps/Browser com.android.browser # # .BrowserTestRunner"
@@ -130,7 +132,7 @@ knownTests=(
"calendar packages/apps/Calendar/tests com.android.calendar.tests # # #"
"calprov content/providers/calendar com.android.providers.calendar.tests # # #"
"camera tests/Camera com.android.cameratests # # CameraInstrumentationTestRunner"
- "contactsprov content/tests/providers/contacts com.android.providers.contacts # com.android.providers.contactstests .ContactsProviderInstrumentation"
+ "contactsprov packages/providers/GoogleContactsProvider/tests com.android.providers.contacts # com.android.providers.contactstests #"
"email packages/apps/Email com.android.email # com.android.email.tests #"
"emailsmall packages/apps/Email com.android.email SmallTests com.android.email.tests #"
"media tests/MediaFrameworkTest com.android.mediaframeworktest # # .MediaFrameworkTestRunner"
@@ -157,13 +159,13 @@ function readConfigFile () {
declare -a lines
exec 3<${rcFile} || exit
while read curline <&3; do
- if [[ -z ${curline} || ${curline:0:1} = "#" ]]; then
+ if [[ -z ${curline} || ${curline:0:1} = "#" ]]; then
continue
fi
lines=("${lines[@]}" "${curline}")
done
exec 3<&-
-
+
# now prepend the user lines (so they can override defaults)
knownTests=("${lines[@]}" "${knownTests[@]}")
fi
@@ -268,14 +270,14 @@ if [[ ${optListTests} -ne 0 ]] ; then
fi
testInfo=($(findTest $1))
-if [[ ${#testInfo[@]} -eq 5 ]] ; then
+if [[ ${#testInfo[@]} -eq 5 ]] ; then
# break out test definition elements
buildPath=${testInfo[0]}
testPackage=${testInfo[1]}
testClass=${testInfo[2]}
runnerPackage=${testInfo[3]}
runnerComponent=${testInfo[4]}
-
+
# replace wildcards with default values
if [[ ${testPackage} == "#" ]] ; then
testPackage=
@@ -284,9 +286,9 @@ if [[ ${#testInfo[@]} -eq 5 ]] ; then
runnerPackage=$testPackage
fi
if [[ ${runnerComponent} == "#" ]] ; then
- runnerComponent="android.test.InstrumentationTestRunner"
+ runnerComponent="android.test.InstrumentationTestRunner"
fi
-
+
if [[ -n ${optTestClass} ]] ; then
testClass=$optTestClass
fi
@@ -294,7 +296,7 @@ if [[ ${#testInfo[@]} -eq 5 ]] ; then
# build & sync, if requested
if [[ ${optSkipBuild} -eq 0 ]] ; then
if [[ ${buildPath} != "#" ]] ; then
- if [[ $optVerbose -ne 0 || ${optPreview} -ne 0 ]] ; then
+ if [[ $optVerbose -ne 0 || ${optPreview} -ne 0 ]] ; then
echo mmm ${buildPath} "&&" adb ${optAdbTarget} remount "&&" adb ${optAdbTarget} sync
fi
if [[ ${optPreview} -eq 0 ]] ; then
@@ -312,7 +314,7 @@ if [[ ${#testInfo[@]} -eq 5 ]] ; then
sleep 2
fi
fi
-
+
# setup additional clauses for the command
classOptions=""
if [[ ${testClass} != "#" ]] ; then
@@ -335,9 +337,9 @@ if [[ ${#testInfo[@]} -eq 5 ]] ; then
if [[ ${optRawMode} -ne 0 ]] ; then
debugOptions="-r "${debugOptions}
fi
-
+
# now run the command
- if [[ $optVerbose -ne 0 || ${optPreview} -ne 0 ]] ; then
+ if [[ $optVerbose -ne 0 || ${optPreview} -ne 0 ]] ; then
echo adb ${optAdbTarget} shell am instrument -w \
${debugOptions} \
${classOptions} \
@@ -354,4 +356,4 @@ else
echo "$progName: unknown test \"$1\"" >&2
exit 1
fi
-
+
diff --git a/tools/scripts/android_rules.xml b/tools/scripts/android_rules.xml
index 1331696fc..ce34e2873 100644
--- a/tools/scripts/android_rules.xml
+++ b/tools/scripts/android_rules.xml
@@ -104,7 +104,7 @@
+ bootclasspathref="android.target.classpath">
diff --git a/tools/scripts/build.template b/tools/scripts/build.template
index c1afef80d..8923428a0 100644
--- a/tools/scripts/build.template
+++ b/tools/scripts/build.template
@@ -45,7 +45,7 @@
-
+
diff --git a/tools/sdkmanager/app/etc/android.bat b/tools/sdkmanager/app/etc/android.bat
index 2aa458dfa..1af1e4788 100755
--- a/tools/sdkmanager/app/etc/android.bat
+++ b/tools/sdkmanager/app/etc/android.bat
@@ -20,6 +20,9 @@ rem Set up prog to be the path of this script, including following symlinks,
rem and set up progdir to be the fully-qualified pathname of its directory.
set prog=%~f0
+rem Grab current directory before we change it
+set workdir=%cd%
+
rem Change current directory to where ddms is, to avoid issues with directories
rem containing whitespaces.
cd %~dp0
@@ -45,4 +48,4 @@ if debug NEQ "%1" goto NoDebug
set jarpath=%frameworkdir%%jarfile%
-call java %java_debug% -Djava.ext.dirs=%frameworkdir% -Djava.library.path=%libdir% -Dcom.android.sdkmanager.toolsdir= -jar %jarpath% %*
+call java %java_debug% -Djava.ext.dirs=%frameworkdir% -Djava.library.path=%libdir% -Dcom.android.sdkmanager.toolsdir= -Dcom.android.sdkmanager.workdir="%workdir%" -jar %jarpath% %*
diff --git a/tools/sdkmanager/app/src/com/android/sdkmanager/CommandLineProcessor.java b/tools/sdkmanager/app/src/com/android/sdkmanager/CommandLineProcessor.java
index ef3d0eec8..d63272df4 100644
--- a/tools/sdkmanager/app/src/com/android/sdkmanager/CommandLineProcessor.java
+++ b/tools/sdkmanager/app/src/com/android/sdkmanager/CommandLineProcessor.java
@@ -16,6 +16,8 @@
package com.android.sdkmanager;
+import com.android.sdklib.ISdkLog;
+
import java.util.HashMap;
import java.util.Map.Entry;
@@ -57,8 +59,10 @@ public class CommandLineProcessor {
* The key is a string "action/longName".
*/
private final HashMap mArguments = new HashMap();
+ private final ISdkLog mLog;
- public CommandLineProcessor(String[][] actions) {
+ public CommandLineProcessor(ISdkLog logger, String[][] actions) {
+ mLog = logger;
mActions = actions;
define(MODE.STRING, false, INTERNAL_FLAG, null, KEY_ACTION, "Selected Action", null);
@@ -564,7 +568,7 @@ public class CommandLineProcessor {
* @param args Format arguments.
*/
protected void stdout(String format, Object...args) {
- System.out.println(String.format(format, args));
+ mLog.printf(format + "\n", args);
}
/**
@@ -575,6 +579,6 @@ public class CommandLineProcessor {
* @param args Format arguments.
*/
protected void stderr(String format, Object...args) {
- System.err.println(String.format(format, args));
+ mLog.error(null, format, args);
}
}
diff --git a/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java b/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java
index 3bcb9a317..b50b113dd 100644
--- a/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java
+++ b/tools/sdkmanager/app/src/com/android/sdkmanager/Main.java
@@ -40,17 +40,28 @@ import java.util.Map;
* Main class for the 'android' application.
*/
class Main {
-
+
+ /** Java property that defines the location of the sdk/tools directory. */
private final static String TOOLSDIR = "com.android.sdkmanager.toolsdir";
+ /** Java property that defines the working directory. On Windows the current working directory
+ * is actually the tools dir, in which case this is used to get the original CWD. */
+ private final static String WORKDIR = "com.android.sdkmanager.workdir";
private final static String[] BOOLEAN_YES_REPLIES = new String[] { "yes", "y" };
private final static String[] BOOLEAN_NO_REPLIES = new String[] { "no", "n" };
+ /** Path to the SDK folder. This is the parent of {@link #TOOLSDIR}. */
private String mSdkFolder;
+ /** Logger object. Use this to print normal output, warnings or errors. */
private ISdkLog mSdkLog;
+ /** The SDK manager parses the SDK folder and gives access to the content. */
private SdkManager mSdkManager;
+ /** Virtual Machine manager to access the list of VMs or create new ones. */
private VmManager mVmManager;
+ /** Command-line processor with options specific to SdkManager. */
private SdkCommandLine mSdkCommandLine;
+ /** The working directory, either null or set to an existing absolute canonical directory. */
+ private File mWorkDir;
public static void main(String[] args) {
new Main().run(args);
@@ -58,23 +69,57 @@ class Main {
/**
* Runs the sdk manager app
- * @param args
*/
private void run(String[] args) {
+ createLogger();
init();
mSdkCommandLine.parseArgs(args);
parseSdk();
doAction();
}
+ /**
+ * Creates the {@link #mSdkLog} object.
+ *
+ * This must be done before {@link #init()} as it will be used to report errors.
+ */
+ private void createLogger() {
+ mSdkLog = new ISdkLog() {
+ public void error(Throwable t, String errorFormat, Object... args) {
+ if (errorFormat != null) {
+ System.err.printf("Error: " + errorFormat, args);
+ if (!errorFormat.endsWith("\n")) {
+ System.err.printf("\n");
+ }
+ }
+ if (t != null) {
+ System.err.printf("Error: %s\n", t.getMessage());
+ }
+ }
+
+ public void warning(String warningFormat, Object... args) {
+ if (mSdkCommandLine.isVerbose()) {
+ System.out.printf("Warning: " + warningFormat, args);
+ if (!warningFormat.endsWith("\n")) {
+ System.out.printf("\n");
+ }
+ }
+ }
+
+ public void printf(String msgFormat, Object... args) {
+ System.out.printf(msgFormat, args);
+ }
+ };
+ }
+
/**
* Init the application by making sure the SDK path is available and
* doing basic parsing of the SDK.
*/
private void init() {
- mSdkCommandLine = new SdkCommandLine();
+ mSdkCommandLine = new SdkCommandLine(mSdkLog);
- /* We get passed a property for the tools dir */
+ // We get passed a property for the tools dir
String toolsDirProp = System.getProperty(TOOLSDIR);
if (toolsDirProp == null) {
// for debugging, it's easier to override using the process environment
@@ -98,15 +143,28 @@ class Main {
}
if (mSdkFolder == null) {
- String os = System.getProperty("os.name");
- String cmd = "android";
- if (os.startsWith("Windows")) {
- cmd += ".bat";
+ errorAndExit("The tools directory property is not set, please make sure you are executing %1$s",
+ SdkConstants.AndroidCmdName());
+ }
+
+ // We might get passed a property for the working directory
+ // Either it is a valid directory and mWorkDir is set to it's absolute canonical value
+ // or mWorkDir remains null.
+ String workDirProp = System.getProperty(WORKDIR);
+ if (workDirProp == null) {
+ workDirProp = System.getenv(WORKDIR);
+ }
+ if (workDirProp != null) {
+ // This should be a valid directory
+ mWorkDir = new File(workDirProp);
+ try {
+ mWorkDir = mWorkDir.getCanonicalFile().getAbsoluteFile();
+ } catch (IOException e) {
+ mWorkDir = null;
+ }
+ if (mWorkDir == null || !mWorkDir.isDirectory()) {
+ errorAndExit("The working directory does not seem to be valid: '%1$s", workDirProp);
}
-
- mSdkCommandLine.printHelpAndExit(
- "ERROR: The tools directory property is not set, please make sure you are executing %1$s",
- cmd);
}
}
@@ -114,33 +172,10 @@ class Main {
* Does the basic SDK parsing required for all actions
*/
private void parseSdk() {
- mSdkLog = new ISdkLog() {
- public void error(Throwable t, String errorFormat, Object... args) {
- if (errorFormat != null) {
- System.err.printf("Error: " + errorFormat, args);
- System.err.println("");
- }
- if (t != null) {
- System.err.print("Error: " + t.getMessage());
- }
- }
-
- public void warning(String warningFormat, Object... args) {
- if (false) {
- // TODO: on display warnings in verbose mode.
- System.out.printf("Warning: " + warningFormat, args);
- System.out.println("");
- }
- }
-
- public void printf(String msgFormat, Object... args) {
- System.out.printf(msgFormat, args);
- }
- };
mSdkManager = SdkManager.createManager(mSdkFolder, mSdkLog);
if (mSdkManager == null) {
- mSdkCommandLine.printHelpAndExit("ERROR: Unable to parse SDK content.");
+ errorAndExit("Unable to parse SDK content.");
}
}
@@ -167,67 +202,108 @@ class Main {
int targetId = mSdkCommandLine.getNewProjectTargetId();
IAndroidTarget[] targets = mSdkManager.getTargets();
if (targetId < 1 || targetId > targets.length) {
- mSdkCommandLine.printHelpAndExit("ERROR: Wrong target id.");
+ errorAndExit("Target id is not valid. Use '%s list -f target' to get the target Ids.",
+ SdkConstants.AndroidCmdName());
}
IAndroidTarget target = targets[targetId - 1];
ProjectCreator creator = new ProjectCreator(mSdkFolder,
- OutputLevel.NORMAL, mSdkLog);
+ mSdkCommandLine.isVerbose() ? OutputLevel.VERBOSE : OutputLevel.NORMAL,
+ mSdkLog);
+
+ String projectDir = getProjectLocation(mSdkCommandLine.getNewProjectLocation());
- creator.createProject(mSdkCommandLine.getNewProjectLocation(),
+ creator.createProject(projectDir,
mSdkCommandLine.getNewProjectName(), mSdkCommandLine.getNewProjectPackage(),
- mSdkCommandLine.getNewProjectActivity(), target, true);
+ mSdkCommandLine.getNewProjectActivity(), target, false /* isTestProject*/);
} else {
mSdkCommandLine.printHelpAndExit(null);
}
}
+ /**
+ * Adjusts the project location to make it absolute & canonical relative to the
+ * working directory, if any.
+ *
+ * @return The project absolute path relative to {@link #mWorkDir} or the original
+ * newProjectLocation otherwise.
+ */
+ private String getProjectLocation(String newProjectLocation) {
+
+ // If the new project location is absolute, use it as-is
+ File projectDir = new File(newProjectLocation);
+ if (projectDir.isAbsolute()) {
+ return newProjectLocation;
+ }
+
+ // if there's no working directory, just use the project location as-is.
+ if (mWorkDir == null) {
+ return newProjectLocation;
+ }
+
+ // Combine then and get an absolute canonical directory
+ try {
+ projectDir = new File(mWorkDir, newProjectLocation).getCanonicalFile();
+
+ return projectDir.getPath();
+ } catch (IOException e) {
+ errorAndExit("Failed to combine working directory '%1$s' with project location '%2$s': %3$s",
+ mWorkDir.getPath(),
+ newProjectLocation,
+ e.getMessage());
+ return null;
+ }
+ }
+
/**
* Displays the list of available Targets (Platforms and Add-ons)
*/
private void displayTargetList() {
- System.out.println("Available Android targets:");
+ mSdkLog.printf("Available Android targets:\n");
int index = 1;
for (IAndroidTarget target : mSdkManager.getTargets()) {
if (target.isPlatform()) {
- System.out.printf("[%d] %s\n", index, target.getName());
- System.out.printf(" API level: %d\n", target.getApiVersionNumber());
+ mSdkLog.printf("[%d] %s\n", index, target.getName());
+ mSdkLog.printf(" API level: %d\n", target.getApiVersionNumber());
} else {
- System.out.printf("[%d] Add-on: %s\n", index, target.getName());
- System.out.printf(" Vendor: %s\n", target.getVendor());
+ mSdkLog.printf("[%d] Add-on: %s\n", index, target.getName());
+ mSdkLog.printf(" Vendor: %s\n", target.getVendor());
if (target.getDescription() != null) {
- System.out.printf(" Description: %s\n", target.getDescription());
+ mSdkLog.printf(" Description: %s\n", target.getDescription());
}
- System.out.printf(" Based on Android %s (API level %d)\n",
+ mSdkLog.printf(" Based on Android %s (API level %d)\n",
target.getApiVersionName(), target.getApiVersionNumber());
// display the optional libraries.
IOptionalLibrary[] libraries = target.getOptionalLibraries();
if (libraries != null) {
+ mSdkLog.printf(" Libraries:\n");
for (IOptionalLibrary library : libraries) {
- System.out.printf(" Library: %s (%s)\n", library.getName(),
- library.getJarName());
+ mSdkLog.printf(" * %1$s (%2$s)\n",
+ library.getName(), library.getJarName());
+ mSdkLog.printf(String.format(
+ " %1$s\n", library.getDescription()));
}
}
}
// get the target skins
String[] skins = target.getSkins();
- System.out.print(" Skins: ");
+ mSdkLog.printf(" Skins: ");
if (skins != null) {
boolean first = true;
for (String skin : skins) {
if (first == false) {
- System.out.print(", ");
+ mSdkLog.printf(", ");
} else {
first = false;
}
- System.out.print(skin);
+ mSdkLog.printf(skin);
}
- System.out.println("");
+ mSdkLog.printf("\n");
} else {
- System.out.println("no skins.");
+ mSdkLog.printf("no skins.\n");
}
index++;
@@ -241,30 +317,29 @@ class Main {
try {
mVmManager = new VmManager(mSdkManager, null /* sdklog */);
- System.out.println("Available Android VMs:");
+ mSdkLog.printf("Available Android VMs:\n");
int index = 1;
for (VmInfo info : mVmManager.getVms()) {
- System.out.printf("[%d] %s\n", index, info.getName());
- System.out.printf(" Path: %s\n", info.getPath());
+ mSdkLog.printf("[%d] %s\n", index, info.getName());
+ mSdkLog.printf(" Path: %s\n", info.getPath());
// get the target of the Vm
IAndroidTarget target = info.getTarget();
if (target.isPlatform()) {
- System.out.printf(" Target: %s (API level %d)\n", target.getName(),
+ mSdkLog.printf(" Target: %s (API level %d)\n", target.getName(),
target.getApiVersionNumber());
} else {
- System.out.printf(" Target: %s (%s)\n", target.getName(), target
+ mSdkLog.printf(" Target: %s (%s)\n", target.getName(), target
.getVendor());
- System.out.printf(" Based on Android %s (API level %d)\n", target
+ mSdkLog.printf(" Based on Android %s (API level %d)\n", target
.getApiVersionName(), target.getApiVersionNumber());
-
}
index++;
}
} catch (AndroidLocationException e) {
- mSdkCommandLine.printHelpAndExit(e.getMessage());
+ errorAndExit(e.getMessage());
}
}
@@ -279,33 +354,43 @@ class Main {
if (targetId >= 1 && targetId <= mSdkManager.getTargets().length) {
target = mSdkManager.getTargets()[targetId-1]; // target it is 1-based
} else {
- mSdkCommandLine.printHelpAndExit(
- "ERROR: Target Id is not a valid Id. Check 'android list target' for the list of targets.");
+ errorAndExit("Target id is not valid. Use '%s list -f target' to get the target Ids.",
+ SdkConstants.AndroidCmdName());
}
-
+
try {
- // default to standard path now
- String vmRoot = AndroidLocation.getFolder() + AndroidLocation.FOLDER_VMS;
-
- Map hardwareConfig = null;
- if (target.isPlatform()) {
- try {
- hardwareConfig = promptForHardware(target);
- } catch (IOException e) {
- mSdkCommandLine.printHelpAndExit(e.getMessage());
+ mVmManager = new VmManager(mSdkManager, mSdkLog);
+
+ String vmName = mSdkCommandLine.getNewVmName();
+ VmInfo info = mVmManager.getVm(vmName);
+ if (info != null) {
+ errorAndExit("VM %s already exists.", vmName);
+ } else {
+ String vmParentFolder = mSdkCommandLine.getNewVmLocation();
+ if (vmParentFolder == null) {
+ vmParentFolder = AndroidLocation.getFolder() + AndroidLocation.FOLDER_VMS;
}
+
+ Map hardwareConfig = null;
+ if (target.isPlatform()) {
+ try {
+ hardwareConfig = promptForHardware(target);
+ } catch (IOException e) {
+ errorAndExit(e.getMessage());
+ }
+ }
+
+ mVmManager.createVm(vmParentFolder,
+ mSdkCommandLine.getNewVmName(),
+ target,
+ mSdkCommandLine.getNewVmSkin(),
+ null /*sdcardPath*/,
+ 0 /*sdcardSize*/,
+ hardwareConfig,
+ mSdkLog);
}
-
- VmManager.createVm(vmRoot,
- mSdkCommandLine.getNewVmName(),
- target,
- null /*skinName*/,
- null /*sdcardPath*/,
- 0 /*sdcardSize*/,
- hardwareConfig,
- null /* sdklog */);
} catch (AndroidLocationException e) {
- mSdkCommandLine.printHelpAndExit(e.getMessage());
+ errorAndExit(e.getMessage());
}
}
@@ -318,10 +403,9 @@ class Main {
String result;
String defaultAnswer = "no";
- System.out.print(String.format("%s is a basic Android platform.\n",
- createTarget.getName()));
- System.out.print(String.format("Do you which to create a custom hardware profile [%s]",
- defaultAnswer));
+ mSdkLog.printf("%s is a basic Android platform.\n", createTarget.getName());
+ mSdkLog.printf("Do you wish to create a custom hardware profile [%s]",
+ defaultAnswer);
result = readLine(readLineBuffer).trim();
// handle default:
@@ -334,7 +418,7 @@ class Main {
return null;
}
- System.out.println(""); // empty line
+ mSdkLog.printf("\n"); // empty line
// get the list of possible hardware properties
File hardwareDefs = new File (mSdkFolder + File.separator +
@@ -349,23 +433,23 @@ class Main {
String description = property.getDescription();
if (description != null) {
- System.out.printf("%s: %s\n", property.getAbstract(), description);
+ mSdkLog.printf("%s: %s\n", property.getAbstract(), description);
} else {
- System.out.println(property.getAbstract());
+ mSdkLog.printf("%s\n", property.getAbstract());
}
String defaultValue = property.getDefault();
if (defaultValue != null) {
- System.out.printf("%s [%s]:", property.getName(), defaultValue);
+ mSdkLog.printf("%s [%s]:", property.getName(), defaultValue);
} else {
- System.out.printf("%s (%s):", property.getName(), property.getType());
+ mSdkLog.printf("%s (%s):", property.getName(), property.getType());
}
result = readLine(readLineBuffer);
if (result.length() == 0) {
if (defaultValue != null) {
- System.out.println(""); // empty line
+ mSdkLog.printf("\n"); // empty line
i++; // go to the next property if we have a valid default value.
// if there's no default, we'll redo this property
}
@@ -384,7 +468,7 @@ class Main {
}
} catch (IOException e) {
// display error, and do not increment i to redo this property
- System.out.println("\n" + e.getMessage());
+ mSdkLog.printf("\n%s\n", e.getMessage());
}
break;
case INTEGER:
@@ -394,7 +478,7 @@ class Main {
i++; // valid reply, move to next property
} catch (NumberFormatException e) {
// display error, and do not increment i to redo this property
- System.out.println("\n" + e.getMessage());
+ mSdkLog.printf("\n%s\n", e.getMessage());
}
break;
case DISKSIZE:
@@ -404,7 +488,7 @@ class Main {
break;
}
- System.out.println(""); // empty line
+ mSdkLog.printf("\n"); // empty line
}
return map;
@@ -458,4 +542,9 @@ class Main {
throw new IOException(String.format("%s is not a valid reply", reply));
}
+
+ private void errorAndExit(String format, Object...args) {
+ mSdkLog.error(null, format, args);
+ System.exit(1);
+ }
}
\ No newline at end of file
diff --git a/tools/sdkmanager/app/src/com/android/sdkmanager/SdkCommandLine.java b/tools/sdkmanager/app/src/com/android/sdkmanager/SdkCommandLine.java
index 918c534d9..39c80b195 100644
--- a/tools/sdkmanager/app/src/com/android/sdkmanager/SdkCommandLine.java
+++ b/tools/sdkmanager/app/src/com/android/sdkmanager/SdkCommandLine.java
@@ -16,6 +16,7 @@
package com.android.sdkmanager;
+import com.android.sdklib.ISdkLog;
import com.android.sdklib.SdkManager;
@@ -38,6 +39,8 @@ public class SdkCommandLine extends CommandLineProcessor {
public static final String KEY_NAME = "name";
public static final String KEY_OUT = "out";
public static final String KEY_FILTER = "filter";
+ public static final String KEY_SKIN = "skin";
+ public static final String KEY_SDCARD_PATH = "sdcard";
public final static String ACTION_LIST = "list";
public final static String ACTION_NEW_VM = ARG_VM;
@@ -52,11 +55,11 @@ public class SdkCommandLine extends CommandLineProcessor {
{ ACTION_NEW_PROJECT,
"Creates a new project using a template." },
{ ACTION_UPDATE_PROJECT,
- "Updates a new project from existing source (must have an AndroidManifest.xml)." },
+ "Updates a project from existing source (must have an AndroidManifest.xml)." },
};
- public SdkCommandLine() {
- super(ACTIONS);
+ public SdkCommandLine(ISdkLog logger) {
+ super(logger, ACTIONS);
define(MODE.ENUM, false, ACTION_LIST, "f", KEY_FILTER,
"List filter", new String[] { ARG_ALL, ARG_TARGET, ARG_VM });
@@ -67,6 +70,10 @@ public class SdkCommandLine extends CommandLineProcessor {
"Name of the new VM", null);
define(MODE.INTEGER, true, ACTION_NEW_VM, "t", KEY_TARGET_ID,
"Target id of the new VM", null);
+ define(MODE.STRING, true, ACTION_NEW_VM, "s", KEY_SKIN,
+ "Skin of the new VM", null);
+ define(MODE.STRING, true, ACTION_NEW_VM, "p", KEY_SDCARD_PATH,
+ "Path to a shared SD card image for the new VM", null);
define(MODE.ENUM, true, ACTION_NEW_PROJECT, "m", KEY_MODE,
"Project mode", new String[] { ARG_ACTIVITY, ARG_ALIAS });
@@ -110,6 +117,17 @@ public class SdkCommandLine extends CommandLineProcessor {
public String getNewVmName() {
return ((String) getValue(ACTION_NEW_VM, KEY_NAME));
}
+
+ /** Helper to retrieve the --skin name for the new vm action. */
+ public String getNewVmSkin() {
+ return ((String) getValue(ACTION_NEW_VM, KEY_SKIN));
+ }
+
+ /** Helper to retrieve the --sdcard name for the new vm action. */
+ public String getNewVmSdCard() {
+ return ((String) getValue(ACTION_NEW_VM, KEY_SDCARD_PATH));
+ }
+
// -- some helpers for project action flags
diff --git a/tools/sdkmanager/app/tests/com/android/sdkmanager/CommandLineProcessorTest.java b/tools/sdkmanager/app/tests/com/android/sdkmanager/CommandLineProcessorTest.java
index e74cdbd62..1a8215121 100644
--- a/tools/sdkmanager/app/tests/com/android/sdkmanager/CommandLineProcessorTest.java
+++ b/tools/sdkmanager/app/tests/com/android/sdkmanager/CommandLineProcessorTest.java
@@ -16,11 +16,15 @@
package com.android.sdkmanager;
+import com.android.sdklib.ISdkLog;
+
import junit.framework.TestCase;
public class CommandLineProcessorTest extends TestCase {
+ private MockStdLogger mLog;
+
/**
* A mock version of the {@link CommandLineProcessor} class that does not
* exits and captures its stdout/stderr output.
@@ -31,8 +35,9 @@ public class CommandLineProcessorTest extends TestCase {
private String mStdOut = "";
private String mStdErr = "";
- public MockCommandLineProcessor() {
- super(new String[][] {
+ public MockCommandLineProcessor(ISdkLog logger) {
+ super(logger,
+ new String[][] {
{ "action1", "Some action" },
{ "action2", "Another action" },
});
@@ -84,9 +89,10 @@ public class CommandLineProcessorTest extends TestCase {
return mStdErr;
}
}
-
+
@Override
protected void setUp() throws Exception {
+ mLog = new MockStdLogger();
super.setUp();
}
@@ -96,7 +102,7 @@ public class CommandLineProcessorTest extends TestCase {
}
public final void testPrintHelpAndExit() {
- MockCommandLineProcessor c = new MockCommandLineProcessor();
+ MockCommandLineProcessor c = new MockCommandLineProcessor(mLog);
assertFalse(c.wasExitCalled());
assertFalse(c.wasHelpCalled());
assertTrue(c.getStdOut().equals(""));
@@ -107,7 +113,7 @@ public class CommandLineProcessorTest extends TestCase {
assertTrue(c.getStdErr().equals(""));
assertTrue(c.wasExitCalled());
- c = new MockCommandLineProcessor();
+ c = new MockCommandLineProcessor(mLog);
assertFalse(c.wasExitCalled());
assertTrue(c.getStdOut().equals(""));
assertTrue(c.getStdErr().indexOf("Missing parameter") == -1);
@@ -119,7 +125,7 @@ public class CommandLineProcessorTest extends TestCase {
}
public final void testVerbose() {
- MockCommandLineProcessor c = new MockCommandLineProcessor();
+ MockCommandLineProcessor c = new MockCommandLineProcessor(mLog);
assertFalse(c.isVerbose());
c.parseArgs(new String[] { "-v" });
@@ -128,7 +134,7 @@ public class CommandLineProcessorTest extends TestCase {
assertTrue(c.wasHelpCalled());
assertTrue(c.getStdErr().indexOf("Missing action name.") != -1);
- c = new MockCommandLineProcessor();
+ c = new MockCommandLineProcessor(mLog);
c.parseArgs(new String[] { "--verbose" });
assertTrue(c.isVerbose());
assertTrue(c.wasExitCalled());
@@ -137,14 +143,14 @@ public class CommandLineProcessorTest extends TestCase {
}
public final void testHelp() {
- MockCommandLineProcessor c = new MockCommandLineProcessor();
+ MockCommandLineProcessor c = new MockCommandLineProcessor(mLog);
c.parseArgs(new String[] { "-h" });
assertTrue(c.wasExitCalled());
assertTrue(c.wasHelpCalled());
assertTrue(c.getStdErr().indexOf("Missing action name.") == -1);
- c = new MockCommandLineProcessor();
+ c = new MockCommandLineProcessor(mLog);
c.parseArgs(new String[] { "--help" });
assertTrue(c.wasExitCalled());
assertTrue(c.wasHelpCalled());
@@ -152,7 +158,7 @@ public class CommandLineProcessorTest extends TestCase {
}
public final void testMandatory() {
- MockCommandLineProcessor c = new MockCommandLineProcessor();
+ MockCommandLineProcessor c = new MockCommandLineProcessor(mLog);
c.parseArgs(new String[] { "action1", "-1", "value1", "-2", "value2" });
assertFalse(c.wasExitCalled());
@@ -161,7 +167,7 @@ public class CommandLineProcessorTest extends TestCase {
assertEquals("value1", c.getValue("action1", "first"));
assertEquals("value2", c.getValue("action1", "second"));
- c = new MockCommandLineProcessor();
+ c = new MockCommandLineProcessor(mLog);
c.parseArgs(new String[] { "action1", "-2", "value2" });
assertFalse(c.wasExitCalled());
assertFalse(c.wasHelpCalled());
@@ -169,7 +175,7 @@ public class CommandLineProcessorTest extends TestCase {
assertEquals(null, c.getValue("action1", "first"));
assertEquals("value2", c.getValue("action1", "second"));
- c = new MockCommandLineProcessor();
+ c = new MockCommandLineProcessor(mLog);
c.parseArgs(new String[] { "action1" });
assertTrue(c.wasExitCalled());
assertTrue(c.wasHelpCalled());
diff --git a/tools/sdkmanager/app/tests/com/android/sdkmanager/SdkCommandLineTest.java b/tools/sdkmanager/app/tests/com/android/sdkmanager/SdkCommandLineTest.java
index b943b98a8..5a2c8e1ef 100644
--- a/tools/sdkmanager/app/tests/com/android/sdkmanager/SdkCommandLineTest.java
+++ b/tools/sdkmanager/app/tests/com/android/sdkmanager/SdkCommandLineTest.java
@@ -16,10 +16,14 @@
package com.android.sdkmanager;
+import com.android.sdklib.ISdkLog;
+
import junit.framework.TestCase;
public class SdkCommandLineTest extends TestCase {
+ private MockStdLogger mLog;
+
/**
* A mock version of the {@link SdkCommandLine} class that does not
* exits and discards its stdout/stderr output.
@@ -28,7 +32,8 @@ public class SdkCommandLineTest extends TestCase {
private boolean mExitCalled;
private boolean mHelpCalled;
- public MockSdkCommandLine() {
+ public MockSdkCommandLine(ISdkLog logger) {
+ super(logger);
}
@Override
@@ -64,6 +69,7 @@ public class SdkCommandLineTest extends TestCase {
@Override
protected void setUp() throws Exception {
+ mLog = new MockStdLogger();
super.setUp();
}
@@ -74,7 +80,7 @@ public class SdkCommandLineTest extends TestCase {
/** Test list with long name and verbose */
public final void testList_Long_Verbose() {
- MockSdkCommandLine c = new MockSdkCommandLine();
+ MockSdkCommandLine c = new MockSdkCommandLine(mLog);
assertEquals("all", c.getListFilter());
c.parseArgs(new String[] { "-v", "list", "--filter", "vm" });
assertFalse(c.wasHelpCalled());
@@ -85,7 +91,7 @@ public class SdkCommandLineTest extends TestCase {
/** Test list with short name and no verbose */
public final void testList_Short() {
- MockSdkCommandLine c = new MockSdkCommandLine();
+ MockSdkCommandLine c = new MockSdkCommandLine(mLog);
assertEquals("all", c.getListFilter());
c.parseArgs(new String[] { "list", "-f", "vm" });
assertFalse(c.wasHelpCalled());
@@ -95,7 +101,7 @@ public class SdkCommandLineTest extends TestCase {
/** Test list with long name and missing parameter */
public final void testList_Long_MissingParam() {
- MockSdkCommandLine c = new MockSdkCommandLine();
+ MockSdkCommandLine c = new MockSdkCommandLine(mLog);
assertEquals("all", c.getListFilter());
c.parseArgs(new String[] { "list", "--filter" });
assertTrue(c.wasHelpCalled());
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java
index 2a2efe7dd..ada61f78d 100644
--- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/AddOnTarget.java
@@ -17,6 +17,8 @@
package com.android.sdklib;
import java.io.File;
+import java.util.Arrays;
+import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
@@ -35,11 +37,13 @@ final class AddOnTarget implements IAndroidTarget {
private final String mJarName;
private final String mJarPath;
private final String mName;
+ private final String mDescription;
- OptionalLibrary(String jarName, String jarPath, String name) {
+ OptionalLibrary(String jarName, String jarPath, String name, String description) {
mJarName = jarName;
mJarPath = jarPath;
mName = name;
+ mDescription = description;
}
public String getJarName() {
@@ -53,6 +57,10 @@ final class AddOnTarget implements IAndroidTarget {
public String getName() {
return mName;
}
+
+ public String getDescription() {
+ return mDescription;
+ }
}
private final String mLocation;
@@ -70,11 +78,11 @@ final class AddOnTarget implements IAndroidTarget {
* @param vendor the vendor name of the add-on
* @param description the add-on description
* @param libMap A map containing the optional libraries. The map key is the fully-qualified
- * library name. The value is the .jar filename
+ * library name. The value is a 2 string array with the .jar filename, and the description.
* @param basePlatform the platform the add-on is extending.
*/
AddOnTarget(String location, String name, String vendor, String description,
- Map libMap, PlatformTarget basePlatform) {
+ Map libMap, PlatformTarget basePlatform) {
if (location.endsWith(File.separator) == false) {
location = location + File.separator;
}
@@ -86,12 +94,16 @@ final class AddOnTarget implements IAndroidTarget {
mBasePlatform = basePlatform;
// handle the optional libraries.
- mLibraries = new IOptionalLibrary[libMap.size()];
- int index = 0;
- for (Entry entry : libMap.entrySet()) {
- mLibraries[index++] = new OptionalLibrary(entry.getValue(),
- mLocation + SdkConstants.OS_ADDON_LIBS_FOLDER + entry.getValue(),
- entry.getKey());
+ if (libMap != null) {
+ mLibraries = new IOptionalLibrary[libMap.size()];
+ int index = 0;
+ for (Entry entry : libMap.entrySet()) {
+ String jarFile = entry.getValue()[0];
+ String desc = entry.getValue()[1];
+ mLibraries[index++] = new OptionalLibrary(jarFile,
+ mLocation + SdkConstants.OS_ADDON_LIBS_FOLDER + jarFile,
+ entry.getKey(), desc);
+ }
}
}
@@ -135,6 +147,8 @@ final class AddOnTarget implements IAndroidTarget {
return mLocation + SdkConstants.OS_IMAGES_FOLDER;
case SKINS:
return mLocation + SdkConstants.OS_SKINS_FOLDER;
+ case DOCS:
+ return mLocation + SdkConstants.FD_DOCS + File.separator;
default :
return mBasePlatform.getPath(pathId);
}
@@ -223,6 +237,11 @@ final class AddOnTarget implements IAndroidTarget {
public void setSkins(String[] skins) {
- mSkins = skins;
+ // we mix the add-on and base platform skins
+ HashSet skinSet = new HashSet();
+ skinSet.addAll(Arrays.asList(skins));
+ skinSet.addAll(Arrays.asList(mBasePlatform.getSkins()));
+
+ mSkins = skinSet.toArray(new String[skinSet.size()]);
}
}
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java
index 0e2b10991..acf1187e0 100644
--- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/IAndroidTarget.java
@@ -58,11 +58,14 @@ public interface IAndroidTarget extends Comparable {
public static int CATEGORIES = 17;
/** OS Path to the "sources" folder. */
public static int SOURCES = 18;
+ /** OS Path to the target specific docs */
+ public static int DOCS = 19;
public interface IOptionalLibrary {
String getName();
String getJarName();
String getJarPath();
+ String getDescription();
}
/**
@@ -82,7 +85,6 @@ public interface IAndroidTarget extends Comparable {
/**
* Returns the full name of the target, possibly including vendor name.
- * @return
*/
String getFullName();
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java
index ede0d86bc..a2de8fc17 100644
--- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkConstants.java
@@ -201,7 +201,18 @@ public final class SdkConstants {
public final static String OS_ADDON_LIBS_FOLDER = FD_ADDON_LIBS + File.separator;
- /* Skin default */
+ /** Skin default **/
public final static String SKIN_DEFAULT = "default";
+ /** Returns the appropriate name for the 'android' command, which is 'android.bat' for
+ * Windows and 'android' for all other platforms. */
+ public static String AndroidCmdName() {
+ String os = System.getProperty("os.name");
+ String cmd = "android";
+ if (os.startsWith("Windows")) {
+ cmd += ".bat";
+ }
+ return cmd;
+ }
+
}
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java
index b4de51aa0..83a90e6c7 100644
--- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/SdkManager.java
@@ -48,6 +48,9 @@ public final class SdkManager {
private final static Pattern PATTERN_PROP = Pattern.compile(
"^([a-zA-Z0-9._-]+)\\s*=\\s*(.*)\\s*$");
+ private final static Pattern PATTERN_LIB_DATA = Pattern.compile(
+ "^([a-zA-Z0-9._-]+\\.jar);(.*)$", Pattern.CASE_INSENSITIVE);
+
/** the location of the SDK */
private final String mSdkLocation;
private IAndroidTarget[] mTargets;
@@ -96,7 +99,9 @@ public final class SdkManager {
/**
* Returns a target from a hash that was generated by {@link IAndroidTarget#hashString()}.
- * @param hash the hash
+ *
+ * @param hash the {@link IAndroidTarget} hash string.
+ * @return The matching {@link IAndroidTarget} or null.
*/
public IAndroidTarget getTargetFromHashString(String hash) {
if (hash != null) {
@@ -213,13 +218,12 @@ public final class SdkManager {
File[] addons = addonFolder.listFiles();
for (File addon : addons) {
+ // Add-ons have to be folders. Ignore files and no need to warn about them.
if (addon.isDirectory()) {
AddOnTarget target = loadAddon(addon, list, log);
if (target != null) {
list.add(target);
}
- } else if (log != null) {
- log.warning("Ignoring add-on '%1$s', not a folder.", addon.getName());
}
}
@@ -247,24 +251,24 @@ public final class SdkManager {
File addOnManifest = new File(addon, SdkConstants.FN_MANIFEST_INI);
if (addOnManifest.isFile()) {
- Map map = parsePropertyFile(addOnManifest, log);
+ Map propertyMap = parsePropertyFile(addOnManifest, log);
- if (map != null) {
+ if (propertyMap != null) {
// look for some specific values in the map.
// we require name, vendor, and api
- String name = map.get(ADDON_NAME);
+ String name = propertyMap.get(ADDON_NAME);
if (name == null) {
displayAddonManifestError(log, addon.getName(), ADDON_NAME);
return null;
}
- String vendor = map.get(ADDON_VENDOR);
+ String vendor = propertyMap.get(ADDON_VENDOR);
if (vendor == null) {
displayAddonManifestError(log, addon.getName(), ADDON_VENDOR);
return null;
}
- String api = map.get(ADDON_API);
+ String api = propertyMap.get(ADDON_API);
PlatformTarget baseTarget = null;
if (api == null) {
displayAddonManifestError(log, addon.getName(), ADDON_API);
@@ -302,22 +306,42 @@ public final class SdkManager {
}
// get the optional description
- String description = map.get(ADDON_DESCRIPTION);
+ String description = propertyMap.get(ADDON_DESCRIPTION);
// get the optional libraries
- String librariesValue = map.get(ADDON_LIBRARIES);
+ String librariesValue = propertyMap.get(ADDON_LIBRARIES);
+ Map libMap = null;
- // split in the string into the values we care about
- String[] libraries = librariesValue.split(";");
- Map libMap = null;
- if (libraries.length > 0) {
- libMap = new HashMap();
- for (String lib : libraries) {
- String[] values = lib.split(":");
- if (values.length == 2) {
- libMap.put(values[0], values[1]);
- } else {
- // TODO: log error
+ if (librariesValue != null) {
+ librariesValue = librariesValue.trim();
+ if (librariesValue.length() > 0) {
+ // split in the string into the libraries name
+ String[] libraries = librariesValue.split(";");
+ if (libraries.length > 0) {
+ libMap = new HashMap();
+ for (String libName : libraries) {
+ libName = libName.trim();
+
+ // get the library data from the properties
+ String libData = propertyMap.get(libName);
+
+ if (libData != null) {
+ // split the jar file from the description
+ Matcher m = PATTERN_LIB_DATA.matcher(libData);
+ if (m.matches()) {
+ libMap.put(libName, new String[] {
+ m.group(1), m.group(2) });
+ } else if (log != null) {
+ log.error(null,
+ "Ignoring library '%1$s', property value has wrong format\n\t%2$s",
+ libName, libData);
+ }
+ } else if (log != null) {
+ log.error(null,
+ "Ignoring library '%1$s', missing property value",
+ libName, libData);
+ }
+ }
}
}
}
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectCreator.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectCreator.java
index 1184fc29b..4cf224d40 100644
--- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectCreator.java
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectCreator.java
@@ -89,13 +89,43 @@ public class ProjectCreator {
String packageName, String activityName, IAndroidTarget target,
boolean isTestProject) {
- // check project folder exists.
+ // create project folder if it does not exist
File projectFolder = new File(folderPath);
- if (projectFolder.isDirectory() == false) {
- mLog.error(null, "Folder '%s' does not exist. Aborting...", folderPath);
- return;
+ if (!projectFolder.exists()) {
+
+ boolean created = false;
+ Throwable t = null;
+ try {
+ created = projectFolder.mkdirs();
+ } catch (Exception e) {
+ t = e;
+ }
+
+ if (created) {
+ println("Created project directory: %1$s", projectFolder);
+ } else {
+ mLog.error(t, "Could not create directory: %1$s", projectFolder);
+ return;
+ }
+ } else {
+ Exception e = null;
+ String error = null;
+ try {
+ String[] content = projectFolder.list();
+ if (content == null) {
+ error = "Project directory %1$s is not a directory.";
+ } else if (content.length != 0) {
+ error = "Project directory %1$s is not empty. Please consider using '%2$s update' instead.";
+ }
+ } catch (Exception e1) {
+ e = e1;
+ }
+
+ if (e != null || error != null) {
+ mLog.error(e, error, projectFolder, SdkConstants.AndroidCmdName());
+ }
}
-
+
try {
// first create the project properties.
@@ -110,6 +140,11 @@ public class ProjectCreator {
PropertyType.DEFAULT);
defaultProperties.setAndroidTarget(target);
defaultProperties.save();
+
+ // create an empty build.properties
+ ProjectProperties buildProperties = ProjectProperties.create(folderPath,
+ PropertyType.BUILD);
+ buildProperties.save();
// create the map for place-holders of values to replace in the templates
final HashMap keywords = new HashMap();
@@ -190,7 +225,7 @@ public class ProjectCreator {
* corresponding value in the created file.
*
* @param templateName the name of to the template file
- * @param dest the path to the destination file, relative to the project
+ * @param destFile the path to the destination file, relative to the project
* @param placeholderMap a map of (place-holder, value) to create the file from the template.
* @param target the Target of the project that will be providing the template.
* @throws ProjectCreateException
@@ -211,7 +246,7 @@ public class ProjectCreator {
* corresponding value in the created file.
*
* @param templateName the name of to the template file
- * @param dest the path to the destination file, relative to the project
+ * @param destFile the path to the destination file, relative to the project
* @param placeholderMap a map of (place-holder, value) to create the file from the template.
* @throws ProjectCreateException
*/
@@ -261,7 +296,6 @@ public class ProjectCreator {
println("Added file %1$s", destFile);
}
-
/**
* Prints a message unless silence is enabled.
* @param format Format for String.format
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectProperties.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectProperties.java
index 473f284f4..938f89d9a 100644
--- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectProperties.java
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/project/ProjectProperties.java
@@ -66,7 +66,7 @@ public final class ProjectProperties {
"# This file must be checked in Version Control Systems.\n" +
"# \n" +
"# To customize properties used by the Ant build system use,\n" +
- "# \"build.properties\", and override values to adapt the script to your" +
+ "# \"build.properties\", and override values to adapt the script to your\n" +
"# project structure.\n" +
"\n";
@@ -74,17 +74,18 @@ public final class ProjectProperties {
// 1-------10--------20--------30--------40--------50--------60--------70--------80
"# This file is used to override default values used by the Ant build system.\n" +
"# \n" +
- "# This file must be checked in Version Control Systems, as it is" +
+ "# This file must be checked in Version Control Systems, as it is\n" +
"# integral to the build system of your project.\n" +
- "# \n" +
- "# Use this file to change values like:\n" +
- "# application-package\n:" +
- "# the name of your application package as defined in the manifest.\n" +
- "# Used by the 'uninstall' rule.\n"+
- "# source-folder\n:" +
- "# the name of the source folder. Default is 'src'.\n" +
- "# out-folder\n:" +
- "# the name of the output folder. Default is 'bin'\n" +
+ "\n" +
+ "# The name of your application package as defined in the manifest.\n" +
+ "# Used by the 'uninstall' rule.\n"+
+ "#application-package=com.example.myproject\n" +
+ "\n" +
+ "# The name of the source folder.\n" +
+ "#source-folder=src\n" +
+ "\n" +
+ "# The name of the output folder.\n" +
+ "#out-folder=bin\n" +
"\n";
private final static Map COMMENT_MAP = new HashMap();
@@ -104,7 +105,9 @@ public final class ProjectProperties {
/**
* Loads a project properties file and return a {@link ProjectProperties} object
* containing the properties
+ *
* @param projectFolderOsPath the project folder.
+ * @param type One the possible {@link PropertyType}s.
*/
public static ProjectProperties load(String projectFolderOsPath, PropertyType type) {
File projectFolder = new File(projectFolderOsPath);
@@ -119,7 +122,44 @@ public final class ProjectProperties {
}
return null;
}
-
+
+ /**
+ * Merges all properties from the given file into the current properties.
+ *
+ * This emulates the Ant behavior: existing properties are not overriden.
+ * Only new undefined properties become defined.
+ *
+ * Typical usage:
+ *
+ * - Create a ProjectProperties with {@link PropertyType#BUILD}
+ *
- Merge in values using {@link PropertyType#DEFAULT}
+ *
- The result is that this contains all the properties from default plus those
+ * overridden by the build.properties file.
+ *
+ *
+ * @param type One the possible {@link PropertyType}s.
+ * @return this object, for chaining.
+ */
+ public ProjectProperties merge(PropertyType type) {
+ File projectFolder = new File(mProjectFolderOsPath);
+ if (projectFolder.isDirectory()) {
+ File defaultFile = new File(projectFolder, type.mFilename);
+ if (defaultFile.isFile()) {
+ Map map = SdkManager.parsePropertyFile(defaultFile, null /* log */);
+ if (map != null) {
+ for(Entry entry : map.entrySet()) {
+ String key = entry.getKey();
+ String value = entry.getValue();
+ if (!mProperties.containsKey(key) && value != null) {
+ mProperties.put(key, value);
+ }
+ }
+ }
+ }
+ }
+ return this;
+ }
+
/**
* Creates a new project properties object, with no properties.
* The file is not created until {@link #save()} is called.
@@ -185,10 +225,9 @@ public final class ProjectProperties {
/**
* Private constructor.
- * Use {@link #load(String)} or {@link #create(String)} to instantiate.
- * @param projectFolderOsPath
- * @param map
- * @param type
+ *
+ * Use {@link #load(String, PropertyType)} or {@link #create(String, PropertyType)}
+ * to instantiate.
*/
private ProjectProperties(String projectFolderOsPath, Map map,
PropertyType type) {
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/vm/HardwareProperties.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/vm/HardwareProperties.java
index cb2c8c228..98e97fe12 100644
--- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/vm/HardwareProperties.java
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/vm/HardwareProperties.java
@@ -91,8 +91,8 @@ public class HardwareProperties {
}
/**
- * Parses the harware definition file.
- * @param buildProp the property file to parse
+ * Parses the hardware definition file.
+ * @param file the property file to parse
* @param log the ISdkLog object receiving warning/error from the parsing.
* @return the map of (key,value) pairs, or null if the parsing failed.
*/
diff --git a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/vm/VmManager.java b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/vm/VmManager.java
index a28561d2a..1edd8b2f8 100644
--- a/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/vm/VmManager.java
+++ b/tools/sdkmanager/libs/sdklib/src/com/android/sdklib/vm/VmManager.java
@@ -20,7 +20,6 @@ import com.android.prefs.AndroidLocation;
import com.android.prefs.AndroidLocation.AndroidLocationException;
import com.android.sdklib.IAndroidTarget;
import com.android.sdklib.ISdkLog;
-import com.android.sdklib.SdkConstants;
import com.android.sdklib.SdkManager;
import java.io.File;
@@ -54,20 +53,20 @@ public final class VmManager {
String name;
String path;
IAndroidTarget target;
-
+
public String getName() {
return name;
}
-
+
public String getPath() {
return path;
}
-
+
public IAndroidTarget getTarget() {
return target;
}
}
-
+
private final ArrayList mVmList = new ArrayList();
private ISdkLog mSdkLog;
@@ -75,7 +74,7 @@ public final class VmManager {
mSdkLog = sdkLog;
buildVmList(sdk);
}
-
+
/**
* Returns the existing VMs.
* @return a newly allocated arrays containing all the VMs.
@@ -83,7 +82,7 @@ public final class VmManager {
public VmInfo[] getVms() {
return mVmList.toArray(new VmInfo[mVmList.size()]);
}
-
+
/**
* Returns the {@link VmInfo} matching the given name.
* @return the matching VmInfo or null if none were found.
@@ -99,7 +98,7 @@ public final class VmManager {
}
/**
- * Creates a new VM.
+ * Creates a new VM. It is expected that there is no existing VM with this name already.
* @param parentFolder the folder to contain the VM. A new folder will be created in this
* folder with the name of the VM
* @param name the name of the VM
@@ -109,27 +108,25 @@ public final class VmManager {
* @param sdcardSize the size of a local sdcard to create. Can be 0 for no local sdcard.
* @param hardwareConfig the hardware setup for the VM
*/
- public static void createVm(String parentFolder, String name, IAndroidTarget target,
+ public VmInfo createVm(String parentFolder, String name, IAndroidTarget target,
String skinName, String sdcardPath, int sdcardSize, Map hardwareConfig,
ISdkLog log) {
-
- // now write the ini file in the vmRoot folder.
- // get the Android prefs location.
+
try {
File rootDirectory = new File(parentFolder);
if (rootDirectory.isDirectory() == false) {
if (log != null) {
- log.error(null, "%s does not exists.", parentFolder);
+ log.error(null, "Folder %s does not exist.", parentFolder);
}
- return;
+ return null;
}
File vmFolder = new File(parentFolder, name + ".avm");
if (vmFolder.exists()) {
if (log != null) {
- log.error(null, "%s already exists.", vmFolder.getAbsolutePath());
+ log.error(null, "Folder %s is in the way.", vmFolder.getAbsolutePath());
}
- return;
+ return null;
}
// create the vm folder.
@@ -164,13 +161,29 @@ public final class VmManager {
// Config file
values.clear();
if (skinName != null) {
- values.put("skin", skinName);
- } else {
- values.put("skin", SdkConstants.SKIN_DEFAULT);
+ // check that the skin name is valid
+ String[] skinNames = target.getSkins();
+ boolean found = false;
+ for (String n : skinNames) {
+ if (n.equals(skinName)) {
+ values.put("skin", skinName);
+ found = true;
+ break;
+ }
+ }
+
+ if (found == false && log != null) {
+ log.warning("Skin '%1$s' does not exists, using default skin.", skinName);
+ }
}
-
+
if (sdcardPath != null) {
- values.put("sdcard", sdcardPath);
+ File sdcard = new File(sdcardPath);
+ if (sdcard.isFile()) {
+ values.put("sdcard", sdcardPath);
+ } else if (log != null) {
+ log.warning("sdcarad image '%1$s' does not exists.", sdcardPath);
+ }
} else if (sdcardSize != 0) {
// TODO: create sdcard image.
}
@@ -182,21 +195,36 @@ public final class VmManager {
File configIniFile = new File(vmFolder, CONFIG_INI);
createConfigIni(configIniFile, values);
- if (target.isPlatform()) {
- System.out.println(String.format(
- "Created VM '%s' based on %s", name, target.getName()));
- } else {
- System.out.println(String.format(
- "Created VM '%s' based on %s (%s)", name, target.getName(),
- target.getVendor()));
+ if (log != null) {
+ if (target.isPlatform()) {
+ log.printf("Created VM '%s' based on %s\n", name, target.getName());
+ } else {
+ log.printf(
+ "Created VM '%s' based on %s (%s)\n", name, target.getName(),
+ target.getVendor());
+ }
}
+
+ // create the VmInfo object, and add it to the list
+ VmInfo vmInfo = new VmInfo();
+ vmInfo.name = name;
+ vmInfo.path = vmFolder.getAbsolutePath();
+ vmInfo.target = target;
+
+ mVmList.add(vmInfo);
+
+ return vmInfo;
} catch (AndroidLocationException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
+ if (log != null) {
+ log.error(e, null);
+ }
} catch (IOException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
+ if (log != null) {
+ log.error(e, null);
+ }
}
+
+ return null;
}
private void buildVmList(SdkManager sdk) throws AndroidLocationException {