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 {